user2204975
user2204975

Reputation: 23

returning two XML nodes at once

I am trying to obtain a list of qux attributes of siblings with a certain attribute, in this case x in attribute foo and y in attribute foo of it's sibling.

//node[@foo="x" and following-sibling::node[@foo="y"]]/@qux | //node[@foo="y" and preceding-sibling::node[@foo="x"]]/@qux

This creates a list, but is the same as running both parts separately and adding them together, except for the order. I need a list of both qux next to eachother, so a list of two qux elements per row, obviously where the siblings match up.

Can this be done in xpath, and if so, how? If not, would xquery do the job?

edit: sample file and output:

<database>
  <ds version="1">
    <node>
     <node foo="x" qux="hello"/>
     <node foo="y" qux="world"/>
    </node>
  </ds>
  <ds version="1">
    <node>
     <node>
       <node foo="x" qux="another"/>
       <node foo="y" qux="sentence"/>
       <node foo="y" qux="example"/>
       <node foo="z" qux="irrelevant"/>
     </node>
    </node>
  </ds>
  <ds version="1">
    <node>
      <node foo="y" qux="not"/>
      <node foo="z" qux="returned"/>
    </node>
  </ds>
</database>

Note that the depth of the node I'm interested in isn't known, so (I think) usage of //node is necessary.

A query should return:

hello world
another sentence
another example

Upvotes: 2

Views: 111

Answers (3)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243519

As per the OP's expressed interest in an XPath 2.0 solution:

This XPath 2.0 expression:

for $n in //node[@foo eq 'x' and following-sibling::*[1][self::node[@foo eq 'y']]]
 return
   ( ($n|$n/following-sibling::*[1])/@qux/string(), '&#xA;')

produces the wanted result.

Upvotes: 1

DeadlyDan
DeadlyDan

Reputation: 699

Its not so easy to get your results with a single XPATH statement- XPATH is intented for XML navigation really. XSL is used for XML transformations (which is really what you want to do, i.e. transform an attribute list [hello][world] into a string "hello world"..) SO here is the XSL you need to get the results you want-

<?xml version="1.0" encoding="UTF-8"?>
<?altova_samplexml file:///C:/Users/Damien/Desktop/testXML.xml?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"     
xmlns:fo="http://www.w3.org/1999/XSL/Format"  
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-
functions">
<xsl:template match="/">    
    <xsl:for-each select="//node[@foo='x' and following-
 sibling::node[@foo='y']]/@qux | //node[@foo='y' and preceding-
 sibling::node[@foo='x']]/@qux">
        <xsl:value-of select="."/>
        <xsl:text> </xsl:text>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Upvotes: 1

forty-two
forty-two

Reputation: 12817

For lack of complete understanding of the requirements, but wouldn't something like this work?

//@qux[../@foo = 'x' or ../@bar='y']

Upvotes: 0

Related Questions