1
votes

I'm trying to use xpath to query for a particular email address in the following XML.

<?xml version="1.0"?>
<records>
        <record>
          <f id="6">sample data 1</f>
          <f id="7">user full name 1</f>
          <f id="8">first name 1</f>
          <f id="9">phone number 1</f>
          <f id="10">[email protected]</f>
          <f id="11">user1 last name</f>
          <f id="12">url 1</f>
        </record>
        <record>
          <f id="6">sample data 2</f>
          <f id="7">user full name 2</f>
          <f id="8">first name 2</f>
          <f id="9">phone number 2</f>
          <f id="10">[email protected]</f>
          <f id="11">user2 last name</f>
          <f id="12">url 2</f>
        </record>
        <record>
          <f id="6">sample data 3</f>
          <f id="7">user full name 3</f>
          <f id="8">first name 3</f>
          <f id="9">phone number 3</f>
          <f id="10">[email protected]</f>
          <f id="11">user3 last name</f>
          <f id="12">url 3</f>
        </record>
      </records>

I'm using PHP and so far I'm able to query for ALL the email addresses by the following line.

$result = $xml->xpath('/records/record/f[@id="10"]');

However, I want to be able to query for a particular email address, e.g. "[email protected]". Can this be done all in one line with xpath?

Also, I need to return some of the other values in the XML based on that email address.

For example, I'd query the XML for "[email protected]" and then return "user full name 2", "sample data 2", etc.

Any help would be appreciated! I'm relatively new to xpath and after trying to look through examples on W3C schools I'm coming up short.

2

2 Answers

2
votes

This would give you the respective <record>:

$xml->xpath('/records/record[f[@id="10"] = "[email protected]"]');

Note that predicates can be nested.


A little more interesting is this, which would also give you the respective <record>

$xml->xpath('/records/record[f = "[email protected]"]');

This works because the XPath = operator compares all matching nodes to the right-hand value. You could read it as "…where any <f> has a value of '[email protected]'.".

Consequently the first expression reads as follows: "…where any <f> with an @id of 10 has a value of '[email protected]'.", i.e. if multiple <f> elements had an ID of 10, it would check them all.

0
votes

You can also accomplish this with navigation instead of a nested predicate condition:

/records/record/f[@id=10 and text()='[email protected]']/..

This says, "navigate down to the fs, find the email address node matching this condition, then get the parent of the node (which is record)." From there you can navigate down to a particular f.