dbinott
dbinott

Reputation: 911

Need to extract data with xmlpath / xmlsearch

I have this XML:

<?xml version="1.0" encoding="utf-8"?> 
<xml>
  <site>
    <id>123</id>
    <po>BT123</po>
  </site>
  <order>
    <shipping>
      <shippingmethod>1</shippingmethod>
      <firstname>Test</firstname>
      <lastname>User</lastname>
      <address>1234 My Place</address>
      <address2>Apt 101</address2>
      <city>Anytown</city>
      <state>AL</state>
      <zip>12345</zip>
    </shipping>
    <orderitems>
      <item>
        <isbn>9780752419930</isbn>
        <rentalterm>1</rentalterm>
      </item>
      <item>
        <isbn>0495599336</isbn>
        <rentalterm>3</rentalterm>
      </item>
      <item>
        <isbn>0743500210</isbn>
        <rentalterm>2</rentalterm>
      </item>
    </orderitems>
  </order>
</xml>

What I want to do is get all the ISBNs where the rental term is not 2 I know how to get ALL the ISBNs:

//item/isbn/text()

and specific rental terms:

//item[rentalterm!=2]

But I am not sure how to put them together. Any suggestions?

Upvotes: 1

Views: 82

Answers (2)

Wayne
Wayne

Reputation: 60414

Use this expression:

//item[not(rentalterm='2')]/isbn/text()

In English: Get the text nodes of any isbn element the parent of which is an item element not having a rentalterm child whose value is equal to 2

Contrast with this expression:

//item[rentalterm!=2]/isbn/text()

...which translates to: Get the text nodes of any isbn element the parent of which is an item element having at least one rentalterm child whose value is not equal to 2.

In other words, this second expression will not match item elements that have no rentalterm children, but will match item elements with multiple rentalterm children as long as at least one does not have a string value equal to 2.

To put it yet another way, the predicate [not(rentalterm='2')] can be read as does not contain a rentalterm child whose string value is equal to 2, whereas [rentalterm!=2] should be read as contains a rentalchild whose string value is not equal to 2.

The spec describes it like this:

If one object to be compared is a node-set and the other is a string, then the comparison will be true if and only if there is a node in the node-set such that the result of performing the comparison on the string-value of the node and the other string is true.

Upvotes: 3

Andy
Andy

Reputation: 9048

Just use:

//item[rentalterm!=2]/isbn/text()

assuming all items have a rentalterm child.

Upvotes: 1

Related Questions