Node -set in xpath

I am writing an xslt stylesheet to convert xml to another xml.

Here is a simplified version of the original xml:

<eml> <datatable> <physical> <distribution id="100"/> </physical> </datatable> <software> <implementation> <distribution id="200"/> </implementation> </software> <additionalMetadata> <describes>100</describes> <describes>200</describes> <describes>300</describes> <describes>400</describes> </additionalMetadata> </eml> 

I am trying to use Xpath to select node -set of β€œdescribes” which does not have a value equal to id //physical/distribution or software/implementation/distribution . In the above case, I want to get node -set:

  <deseribes>300</describes> <deseribes>400</describes> 

(100 and 200 are attribute identifier values //physical/distribution or software/implementation/distribution ).

I wrote something like:

 <xsl:with-param name="describes-list" select="./describes[//physical/distribution/@id !=. and //software/implementation/distribution/@id != .] "/> 

He is working on the above example. However, the data and software item is repeatable. So this xml is valid:

 <eml> <datatable> <physical> <distribution id="100"/> </physical> </datatable> <datatable> <physical> <distribution id="300"/> </physical> </datatable> <software> <implementation> <distribution id="200"/> </implementation> </software> <additionalMetadata> <describes>100</describes> <describes>200</describes> <describes>300</describes> <describes>400</describes> </additionalMetadata> </eml> 

But my xslt does not work on the above example :(

Could you shed some light on this? Thank you in advance!

Jing

+6
xml xpath xslt
source share
1 answer

This is a frequently made mistake. Never use XPath "! =" Operator when one or both of the operands are node-set (s).

value != node-set

by definition, is true if node n exists in node -set, so

value not equal to string(n)

Do you want to

value not equal to any node in node-set.

This can be expressed as follows:

value = node-set

true if there is at least one node n in node -set such that:

value = string(n)

Then

not(value = node-set)

true if node n does not exist in node-set, so

value = string(n)

Therefore, the following XPath expression will select the nodes you want :

  / * / * / describes [not (. = ../../*/physical/distribution/@id)
               and 
                 not (. = ../../*/implementation/distribution/@id)]

I personally would prefer to have only one node context comparison with combining two node-sets:

  / * / * / describes
             [not (. = (../../*/physical/distribution/@id
                     | 
                       ../../*/implementation/distribution/@id
                      )
                  )
             ]

Please note that I do not use the abbreviation "//" . This is usually very expensive (inefficient) and should only be used if we do not know the structure of the XML document.

And, of course, the XPath expressions above should be evaluated against the following XML document (the second of them in the question):

  <eml>
     <datatable>
         <physical>
             <distribution id = "100" />
         </physical>
     </datatable>
     <datatable>
         <physical>
             <distribution id = "300" />
         </physical>
     </datatable>
     <software>
         <implementation>
             <distribution id = "200" />
         </implementation>
     </software>
     <additionalMetadata>
         <describes> 100 </describes>
         <describes> 200 </describes>
         <describes> 300 </describes>
         <describes> 400 </describes>
     </additionalMetadata>
 </eml>
+19
source share

All Articles