Here is the xml snippet:
$ cat short.xml
<hostnames>
<hostname name="yahoo.com" type="user"/>
<hostname name="ir1.fp.vip.sp2.yah开发者_StackOverflow社区oo.com" type="PTR"/>
</hostnames>
<hostnames>
<hostname name="Inc.com" type="user"/>
<hostname name="www.inc.com" type="PTR"/>
</hostnames>
The desired output is:
yahoo.com | ir1.fp.vip.sp2.yahoo.com
Inc.com | www.inc.com
What I have so far that is only partially working: $ xml sel -t -m "//hostname" -v "@name" -n short.xml
I cannot seem to trap the Type= condition properly. TIA.
Two more solutions using xmlstarlet only once (no need to iterate):
xmlstr='
<root>
<hostnames>
<hostname name="yahoo.com" type="user"/>
<hostname name="ir1.fp.vip.sp2.yahoo.com" type="PTR"/>
</hostnames>
<hostnames>
<hostname name="Inc.com" type="user"/>
<hostname name="www.inc.com" type="PTR"/>
</hostnames>
</root>
'
echo "$xmlstr" | xmlstarlet sel -T -t -m "//hostnames" -m "hostname[@type='user']" -v '@name' -o " | " -b -m "hostname[@type='PTR']" -v '@name' -n
echo "$xmlstr" | xmlstarlet sel -T -t -m "//hostname" -i "@type='user'" -v '@name' -o " | " -b -i "@type='PTR'" -v '@name' -n
You need to count the hostnames with xmlstarlet el
or something and then iterate with something like:
xmlstarlet sel -t -c "//hostnames[1]" short.xml | xmlstarlet sel -t -m "//hostname/@name" -v . -o ' | '
This would be a lot easier if the XML was better designed. :)
The example given in question is invalid xml.
xmlstarlet --version
1.3.1
compiled against libxml2 2.8.0, linked with 20800
compiled against libxslt 1.1.26, linked with 10126
xmlstarlet val -e short.xml
short.xml:5.1: Extra content at the end of the document
<hostnames>
^
short.xml - invalid
The idea in the answer by mitm is quite nice cure.
$ xml sel -t -m //hostnames -v "concat(hostname[1]/@name,'|',hostname[2]/@name)" -n file.xml
$ xml sel -t -m //hostnames -v hostname[1]/@name -o "|" -v hostname[2]/@name -n file.xml
$ xml sel -t -m //hostname[@type='user'] -v @name -o "|" -v following-sibling::hostname/@name -n file.xml
精彩评论