Search code examples
xmlxmllint

Get all attribute values from XML


I have the following XML sample file.

<root>
<ul id="nav">
    <li id="id1">some</li>
    <li id="id2"> unimportant
        </li>
    <li id="id3"> text.
        </li>
</ul>

<ul id="tag">
    <li id="id1">SOME</li>
    <li id="id2"> MORE
        </li>
    <li id="id3"> TEXT.
        </li>
</ul>
</root>

I would like to use xmllint to extract all attribute values of all <li> elements which are listed under <ul id="nav">.

I can use

xmllint --xpath '//ul[@id="nav"]/li/@id' sample.xml

which will return

id="id1" id="id2" id="id3"

However, I would like to get

id1 id2 id3

I tried

xmllint --xpath 'string(//ul[@id="nav"]/li/@id)' sample.xml

but this only return the value of the first attribute

id1

Can I extract all values without resorting to other tools like awk, sed etc.? They may be delimited by either space or newline, it does not really matter in my case.


Solution

  • If you can use xmlstarlet, you can use the -v (--value-of) command line option:

    xmlstarlet sel -t -v "//ul[@id='nav']/li/@id" sample.xml
    

    I don't think you can use HTML as an input for the sel command, but I could be wrong.

    I know you can with the tr (translate) command though (with --html). Then you could use an XSLT...

    xmlstarlet tr --html sample.xsl sample.xml
    

    XSLT (sample.xsl)

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="text"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="/">
        <xsl:for-each select="//ul[@id='nav']/li/@id">
          <xsl:value-of select="concat(.,'&#xA;')"/>
        </xsl:for-each>
      </xsl:template>
    
    </xsl:stylesheet>