How can I get the value from an attribute using xmllint and XPath?

61,048

Solution 1

You need to use fn:string(), which will return the value of its argument as xs:string. In case its argument is an attribute, it will therefore return the attribute's value as xs:string.

test=$(xmllint --xpath "string(//body/value/@name)" test.xml)

Solution 2

Try this, it's not beautiful but it works :)

I just erase lines containing > from stdout , cut the string to get the second part after the = , and delete "

test=$(echo 'cat //body/value/@name' | xmllint --shell "test.xml" | grep -v ">" | cut -f 2 -d "=" | tr -d \"); 
echo $test

Solution 3

An approach with a helper awk command that supports multiple attributes (a streamlined version of ego's approach):

echo 'cat //*/@name' | xmllint --shell file | awk -F\" 'NR % 2 == 0 { print $2 }'

The awk command:

  • splits xmllint's output lines into fields by " chars. (-F\")

    • Note that xmllint normalizes quoting around attribute values to "..." on output, even if the input had '...', so it's sufficient to split by ".
  • only processes even-numbered lines (NR %2 == 0), thereby filtering out the separator lines that cat invariably prints.

  • print $2 then prints only the 2nd field, which is the value of each attribute without the enclosing "...".

Assuming the following sample XML in file:

<body>
  <value name="abc"></value>
  <value name="def"></value>
</body>

the above yields:

abc
def

Solution 4

I recently had to port my original simpler solution using --xpath to a platform lacking this feature, so had to adopt the "cat" solution too. This will handle multiple matches, tested on Ubuntu 12.04 and Solaris 11:

getxml() { # $1 = xml file, $2 = xpath expression
    echo "cat $2" | xmllint --shell $1 |\
    sed -n 's/[^\"]*\"\([^\"]*\)\"[^\"]*/\1/gp'
}

e.g. extracting instance names from a glassfish domain config:

$ getxml /tmp/test.xml "//server[@node-ref]/@name"
inst1
inst2

The sed post-processing just grabs all quoted values which was adequate for my needs (getting bits of glassfish config).

Share:
61,048
Tran Ngu Dang
Author by

Tran Ngu Dang

Geek forever !!!

Updated on November 05, 2021

Comments

  • Tran Ngu Dang
    Tran Ngu Dang over 2 years

    I want to get the value of name and put it in a variable using XMLLint

    <body>
    <value name="abc"></value>
    </body>
    
    echo 'cat //body/value/@name' | xmllint --shell "test.xml"
    
    / >  -------
     name="abc"
    / > 
    

    So I want to assign the value "abc" to variable $test

  • Fergie
    Fergie over 11 years
    unfortunately --xpath is unsupported on a lot of installations
  • badp
    badp about 9 years
    Use xmllint so you don't have to use REs to parse XML. Realize you have to use REs to parse the output of xmllint.
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com over 8 years
    This only shows the value for a single element, is it possible to get multiple matches?
  • आनंद
    आनंद over 7 years
    why does it print ------- before the name attribute value? how to remove it?
  • dieHellste
    dieHellste over 6 years
    this works perfectly for me, thanks. Do you also have a nice way of assigning the values to different variables. Like VAR_1=$(echo 'cat //*/@name' | xmllint --shell file | awk -F\" 'NR % 2 == 0 { print $2 }') ?
  • mklement0
    mklement0 over 6 years
    @dieHellste: You can read the output lines into variables (either in a while loop or, in Bash, into an array with read -a); if you need further guidance, please ask a new question.
  • MariusMatutiae
    MariusMatutiae almost 4 years
    @CiroSantilli郝海东冠状病六四事件法轮功 You can get multiple matches with xmllint --xpath "//body/value/@name", but they will be all on the same line, unless you have version 2.9.9 or newer of the package libmxl2-utils.