2008-12-01 19 views
6

Estoy escribiendo una hoja de estilo xslt para transformar un xml en otro xml.node-set en xpath

Aquí es la versión simplificada de XML original:

<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> 

intento utilizar un XPath para seleccionar conjunto de nodos de "describe" que no tiene el valor que es igual al valor de la identificación de //physical/distribution o software/implementation/distribution. En caso anterior, quiero para obtener el conjunto de nodos:

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

(100 y 200 son los valores de atributo id de //physical/distribution o software/implementation/distribution).

escribí algo como:

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

Funciona en el ejemplo anterior. Sin embargo, el elemento de la tabla de datos y el software son repetibles. Así que esto es válido xml:

<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> 

Pero mi XSLT no funciona en el ejemplo anterior :(

¿le importaría arrojar algo de luz sobre este Gracias de antemano

Jing

?!

Respuesta

19

Este es un error a menudo comprometida. Nunca utilice XPath's "!=" operator cuando uno o ambos de los operandos es/son conjunto de nodos (s).

      value != node-set

por definición es cierto si existe un nodo n en el conjunto de nodos, de manera que

      value no es igual a string(n)

Lo que queremos es que

      value no es igual a cualquiera nodo en el conjunto de nodos.

Esto se puede expresar de la siguiente manera:

      value = node-set

es cierto si existe al menos un nodo n en conjunto de nodos, de manera que:

      value = string(n)

Luego

      not(value = node-set)

es cierto si no existe ningún nodo n en conjunto de nodos, de manera que

      value = string(n)

Por lo tanto, la siguiente expresión XPath seleccionará los nodos deseados:

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

Yo personalmente preferiría tener sólo una comparación del nodo de contexto a la unión de los dos conjuntos de nodos:

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

Por favor, tenga en cuenta que evito usar el "//" abreviatura. Por lo general, es muy costoso (ineficiente) y debe usarse solo si no conocemos la estructura del documento XML.

Y, por supuesto, las expresiones XPath anteriores tienen que ser eavaluated contra el siguiente documento XML (el segundo proporcionada en la pregunta):

 
<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>