1

MY xml

<?xml version="1.0" encoding="UTF-8" ?>
<Attributes>
   <Attribute>123</Attribute>
   <Attribute>959595</Attribute>
   <Attribute>1233</Attribute>
   <Attribute>jiji</Attribute>
</Attributes>

I need to get the tag value of second occurence of attribute tag i.e 959595 using sed

i used the command

sed -n ':a;$!{N;ba};s#\(<Attribute\)\(.*\)\(</Attribute>\)#\1#2#\2#p' file

pattern one second occurrence pattern two value it doesnt work

i dont know whether my approach is correct or not please correct my command

Avinash Raj
  • 172,303
  • 28
  • 230
  • 274
bananagator
  • 551
  • 3
  • 8
  • 26
  • I would rather use an XML aware command line tool - e.g.http://stackoverflow.com/questions/91791/grep-and-sed-equivalent-for-xml-command-line-processing – Brian Agnew Nov 05 '14 at 16:43

4 Answers4

2

The proper way to do this is :

$ xmllint --xpath '/Attributes/Attribute[2]/text()' file.xml

NOTES

  • xmllint comes with libxml2.
  • the '2' is the second searched element
Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
0
sed -n '/<Attributes>/,\#</Attributes># {
  /<Attribute>/ {
     H;g
     s#.*<Attribute>\(.*\)</Attribute>.*#\1#
     t found
     }
   b
:found
   p;q
   }' YourFile
  • Assuming, like in your sample, there is only 1 Attributes to found, this sed only return the 1st. (if the xml content is only like your sample, the /<Attributes>/,\#</Attributes># selection is not needed)
  • Posix version so --posix on GNU sed
NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43
  • If you put an n on you will get the next entry (I think its what the OP wants): sed -n '//,\## { // { H;g;n; s#.*\(.*\).*#\1# t found } b :found p;q }' attrib.txt –  Nov 06 '14 at 11:03
  • not the same. `n` will add the next line to the working buffer without condition (unless last line) and this could be something else than , this is why i filter and use holding buffer – NeronLeVelu Nov 06 '14 at 13:50
  • I tested it on my system and it works you already have the /Attribute/ addressing on for the statement, so you probably don't need much of the other things. –  Nov 06 '14 at 15:54
  • test with `123` or simply with `1` content (all with new line between tags) – NeronLeVelu Nov 06 '14 at 16:22
  • I used the test data from the OP, he wants the second Attribute entry not the first one. –  Nov 06 '14 at 16:28
  • that is the main problem, is the real data exactly in the same structure. I assume partially this a secure a bit. If really the same, your remarq is OK. This is why, on XML, advice is to use xmlparser if available/possible – NeronLeVelu Nov 06 '14 at 16:38
  • I agree an XML parser is more useful if you need to do anything extensive but for simple value if you know sed its widely available. I just generalized my answer a little bit to select what values to parse, but I wouldn't put much more effort than that. –  Nov 06 '14 at 17:30
0

This sed prints all Attribute entries from the Attributes block, then takes the second entry and removes the tags:

sed -n '/<Attributes>/,\#</Attributes>#{/<Attribute>/p}' attrib.txt | sed -n '2p' | sed 's#</Attribute>##;s/<Attribute>//'

Output: 
   959595

Or another way without pipes is to use sed commands, this goes to the second entry strips the Attribute tag and then quits:

sed -n '/<Attributes>/,\#</Attributes>#{/<Attribute>/{n;s#.*<Attribute>\(.*\)</Attribute>.*#\1#;p;q};}' attrib.txt

Or if your number of Attribute entries changes you can make it a bit more intuitive by parsing all values and then using sed to print the attribute placement where you want:

sed -n '/<Attributes>/,\#</Attributes>#{/<Attribute>/{s#</Attribute>##;s#<Attribute>##;p}}' attrib.txt | sed -n '2p'

You can change the end where from 2, to whatever Attribute value field you want to display or take multiple values like sed -n '2p;3p' or sed -n '1,2p'

0

I also would follow the xmllint xpath way. It however seems like there is two versions available. According to this man page at https://linux.die.net/man/1/xmllint there is no xpath parameter, but it is called "pattern".

Following this documentation, your call then would be

$ xmllint --pattern '/Attributes/Attribute[2]/text()' file.xml

I recommend checking your local man page to see which one to use.

Kai
  • 37
  • 5