在xpath中设置节点

时间:2008-12-01 22:22:21

标签: xml xslt xpath

我正在编写一个xslt样式表来将xml转换为另一个xml。

以下是原始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>

我尝试使用Xpath来选择“describe”的节点集,该节点集的值不等于//physical/distributionsoftware/implementation/distribution的id值。在上面的例子中,我想得到节点集:

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

(100和200是//physical/distributionsoftware/implementation/distribution的属性ID值。

我写了类似的东西:

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

它适用于上面的例子。但是,数据表和软件的元素是可重复的。所以这个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>

但是我的xslt在上面的例子中不起作用:(

你介意对此有所了解吗?提前谢谢!

1 个答案:

答案 0 :(得分:19)

这是一个经常犯的错误。当一个或两个操作数是节点集时,切勿使用XPath's "!=" operator

value != node-set

如果节点集中存在节点n,则

定义为

value不等于string(n)

你想要的是

value不等于节点集中的任何节点。

这可以用以下方式表达:

value = node-set

如果节点集中至少存在一个节点n,则

为真,例如:

value = string(n)

然后

not(value = node-set)

如果节点集中不存在任何节点n,则

为真,例如

value = string(n)

因此,以下XPath表达式将选择所需的节点

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

我个人更愿意将上下文节点与两个节点集的并集进行一次比较:

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

请注意我避免使用“//”缩写。它通常非常昂贵(效率低​​下),只有在我们不知道XML文档的结构时才应该使用它。

当然,上述XPath表达式必须针对以下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>