MathewS
MathewS

Reputation: 11

Find attribute of parent element using a known element

Not sure if the title is clear but basically I have some XML like the following:

<details>
<result id=1234567890>
    <name>Test1</name>
</result>
<result id=5345345433>
    <name>Test2</name>
</result>
<result id=9572385354>
    <name>Test3</name>
</result>

What I'm trying to accomplish is to find the id attribute of using the known value of i.e. Test1 > 1234567890, Test2 > 5345345433, Test3 > 9572385354

Preferably by using xmllint but xmlstarlet is also an option.

Upvotes: 1

Views: 1229

Answers (5)

something like this should work with xmlstarlet (worked for me) :

xmlstarlet sel --template --match "/details/result[name='Test1']" --value-of "@id" test.xml

Upvotes: 0

mush4brains
mush4brains

Reputation: 1

To answer the OP's question in full,

#/bin/bash
#
# how to use xmllint to get information from specific elements
# REQUIRES libxml2 (sorry Snow Leopard!)

mytestxml='
<details>
    <result id="1234567890">
            <name>Test1</name>
    </result>
    <result id="5345345433">
            <name>Test2</name>
    </result>
    <result id="9572385354">
        <name>Test3</name>
    </result>
</details>
'
echo Test Document is :"$mytestxml"
echo Get the contents of the \''id'\' attribute of a specific \''result'\' element
query=\''string(/details/result[3]/@id)'\'
echo xpath query is "$query"
myresult=$(echo "$mytestxml" | xmllint --xpath 'string(/details/result[3]/@id)' - )
echo info returned is "$myresult"
echo ""

echo Get the specific \''result'\' node whose \''name'\' element is \"Test1\"
query=\''/details/result[name="Test1"]'\'               
echo xpath query is "$query"
myresult=$(echo "$mytestxml" | xmllint --xpath '/details/result[name="Test1"]' - )
echo info returned is "$myresult"
echo ""

echo Get the \''id'\' attribute of the specific \''result'\' node whose \''name'\' element is \"Test1\"
query=\''string(/details/result[name="Test1"]/@id)'\'
echo combined xpath query is "$query"
myresult=$(echo "$mytestxml" | xmllint --xpath 'string(/details/result[name="Test1"]/@id)' - )
echo info returned is "$myresult"
    • Get the contents of the 'id' attribute of a specific 'result' element.

xpath query is :

    'string(/details/result[3]/@id)'

info returned is : 9572385354

    • Get the specific 'result' node whose 'name' element is "Test1"

xpath query is :

    '/details/result[name="Test1"]'

info returned is :

    <result id="1234567890">
        <name>Test1</name>
    </result>
    • Get the 'id' attribute of the specific 'result' node whose 'name' element is "Test1"

combined xpath query is :

    'string(/details/result[name="Test1"]/@id)'

info returned is 1234567890

Hope this proves useful to other's who find this page. :o)

Upvotes: 0

ddoxey
ddoxey

Reputation: 2063

Perhaps a simple grep & awk solution will work for you.

grep -B1 Test1 sample.xml | awk '/id=/{gsub(/[^0-9]+/, "", $0); print $0 }'

Upvotes: 0

L&#233;a Gris
L&#233;a Gris

Reputation: 19545

You can also use xmllint:

xmllint --xpath "string(/details/result[name='Test1']/@id)" yourfile.xml

--xpath: tells xmllint to select using the xpath syntax.

Details of the xpath selector:

string(/details/result[name='Test1']/@id)

string(): Make a string

/details/result: select the result child element of the details element

[name='Test1']: containing a name node whose value is Test1

/@id: id attribute value (of the result element)

Upvotes: 2

user3559631
user3559631

Reputation: 53

Input

First, your XML is invalid. Your id properties need to be qouted, and the details is not closed. Here is the revised input:

<details>
  <result id="1234567890">
    <name>Test1</name>
  </result>
  <result id="5345345433">
    <name>Test2</name>
  </result>
  <result id="9572385354">
    <name>Test3</name>
  </result>
</details>

Result

The following will extract the specific id given the name property using xmlstarlet.

 xmlstarlet sel -t -c "/details/result[name='Test1']" test.xml | grep -Po "(?<=id=\")[\d]*"

This will return

 1234567890

You can also replace Test1 in the command with a variable.

 var=Test1
 xmlstarlet sel -t -c "/details/result[name='$var']" test.xml | grep -Po "(?<=id=\")[\d]*"

Breakdown

 xmlstarlet sel -t -c "/details/result[name='$var']" test.xml

Select all name tags inside results matching $var.

 | grep -Po "(?<=id=\")[\d]*"

Pipe the output to grep with Perl Regex to look for the id property and print all containing digits.

Upvotes: 2

Related Questions