简体   繁体   中英

read and concatenate xml attributes using shell script

I have an xml:

<element attr1="val11" attr2="val12" attr3="val13" />
<element attr1="val21" attr2="val22" attr3="val23" />
<element attr1="val31" attr2="val32" attr3="val33" />

I need to get an output like below, using shell script:

val11(val13)
val21(val23)
val31(val33)

awk -F'attr1 =“ | attr3 =” |“''{print $ 2”(“ $(NF-1)”)“}'文件

The right way to extract contents from XML is with a real, live XML parser. XMLStarlet is onesuch.

Note that this requires your data to be actual XML , which your existing data isn't without a root element being added.

xmlstarlet sel -t -m '//element' -v ./@attr1 -o '(' -v ./@attr3 -o ')' -n <<EOF
<root>
<element attr1="val11" attr2="val12" attr3="val13" />
<element attr1="val21" attr2="val22" attr3="val23" />
<element attr1="val31" attr2="val32" attr3="val33" />
</root>
EOF

To explain how this works:

  • -t starts a new template
  • -m //element matches an element named element anywhere in your document.
  • -v ./@attr1 emits the content of the attribute named attr1
  • -o '(' emits a literal ( as a string
  • -v ./@attr3 emits the content of the attribute named attr3
  • -o ')' emits a literal ) as a string
  • -n emits a literal newline

If you want to be able to run this on machines that don't have XMLStarlet installed, you can generate an XSLT template, and invoke that with XSLTProc, which is widely available.

Running xmlstarlet sel -C -t -m '//element' -v ./@attr1 -o '(' -v ./@attr3 -o ')' -n emits the following XSLT file:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
  <xsl:output omit-xml-declaration="yes" indent="no"/>
  <xsl:template match="/">
    <xsl:for-each select="//element">
      <xsl:call-template name="value-of-template">
        <xsl:with-param name="select" select="./@attr1"/>
      </xsl:call-template>
      <xsl:text>(</xsl:text>
      <xsl:call-template name="value-of-template">
        <xsl:with-param name="select" select="./@attr3"/>
      </xsl:call-template>
      <xsl:text>)</xsl:text>
      <xsl:value-of select="'&#10;'"/>
    </xsl:for-each>
  </xsl:template>
  <xsl:template name="value-of-template">
    <xsl:param name="select"/>
    <xsl:value-of select="$select"/>
    <xsl:for-each select="exslt:node-set($select)[position()&gt;1]">
      <xsl:value-of select="'&#10;'"/>
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

If you save this as myproc.xslt , and run xsltproc myproc.xslt - <input.xml , you'll get the desired output on stdout.

awk '{split($2,a,"=");split($4,b,"=");gsub(/"/,"",a[2]);gsub(/"/,"",b[2]);print a[2]"("b[2] ")"}' xml
val11(val13)
val21(val23)
val31(val33)

you can also use sed as below;

sed 's/^.*1="//g;s/" .*.="/(/;s/" \/>/)/g' yourXMl

Example;

user@host:/tmp$ sed 's/^.*1="//g;s/" .*.="/(/;s/" \/>/)/g' t1
val11(val13)
val21(val23)
val31(val33)

OR.. we can do this with perl..

Tested on CentOS7

cat your file to this filter as shown below...

Tue Oct 04|22:41:36|gaurav@[STATION]:/root/ga/scripts/temp> cat c.txt
<element attr1="val11" attr2="val12" attr3="val13" />
<element attr1="val21" attr2="val22" attr3="val23" />
<element attr1="val31" attr2="val32" attr3="val33" />
Tue Oct 04|22:41:38|gaurav@[STATION]:/root/ga/scripts/temp> cat c.txt |perl -pe 's/^.+r1=\"(.+?)\".+r3=\"(.+?)\" .*$/\1(\2)/g'
val11(val13)
val21(val23)
val31(val33)
Tue Oct 04|22:41:40|gaurav@[STATION]:/root/ga/scripts/temp>

awk -F'[="]' '{print $3 "("$(NF-1)")"}' file

val11(val13)
val21(val23)
val31(val33)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM