How can I get the value from an attribute using xmllint and XPath?
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"
.
- Note that
only processes even-numbered lines (
NR %2 == 0
), thereby filtering out the separator lines thatcat
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).
Comments
-
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 over 11 yearsunfortunately --xpath is unsupported on a lot of installations
-
badp about 9 yearsUse 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 over 8 yearsThis only shows the value for a single element, is it possible to get multiple matches?
-
आनंद over 7 yearswhy does it print ------- before the name attribute value? how to remove it?
-
dieHellste over 6 yearsthis 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 over 6 years@dieHellste: You can
read
the output lines into variables (either in awhile
loop or, in Bash, into an array withread -a
); if you need further guidance, please ask a new question. -
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.