首页 > 解决方案 > 如何使用 XPath 比较多个节点

问题描述

鉴于下面的 XML,我正在尝试编写一个仅返回此匹配项的 XPath:

<TOKEN BEGIN="17" END="19" SENTENCE_BEGIN="0" SENTENCE_END="156" PROP="C" DOUBLE="YES" />

这是输入文件:

<?xml version="1.0" encoding="utf-8"?>
<DOCUMENT>
  <SECTION>
    <PARAGRAPH TRACK="4">
      <SENTENCE NAME="PRIMARY" COUNT="4">
        <TOKEN BEGIN="9" END="11" SENTENCE_BEGIN="0" SENTENCE_END="156" />
        <TOKEN BEGIN="32" END="37" SENTENCE_BEGIN="0" SENTENCE_END="156" />
        <TOKEN BEGIN="167" END="169" SENTENCE_BEGIN="158" SENTENCE_END="316" />
        <TOKEN BEGIN="210" END="215" SENTENCE_BEGIN="158" SENTENCE_END="316" />
      </SENTENCE>
      <SENTENCE NAME="SECONDARY" COUNT="2">
        <TOKEN BEGIN="139" END="141" SENTENCE_BEGIN="0" SENTENCE_END="156" PROP="A" DOUBLE="YES" />
        <TOKEN BEGIN="143" END="145" SENTENCE_BEGIN="0" SENTENCE_END="156" PROP="B" />
      </SENTENCE>
      <SENTENCE NAME="SECONDARY" COUNT="1">
        <TOKEN BEGIN="17" END="19" SENTENCE_BEGIN="0" SENTENCE_END="156" PROP="C" DOUBLE="YES" />
      </SENTENCE>
    </PARAGRAPH>
  </SECTION>
</DOCUMENT>

这是我的 xpath 字符串:

//TOKEN [@DOUBLE] [@BEGIN <= ../../SENTENCE[@NAME='PRIMARY']/TOKEN/@END] [ (@SENTENCE_BEGIN = ../../SENTENCE[@NAME='PRIMARY']/TOKEN/@SENTENCE_BEGIN) and (@SENTENCE_END = ../../SENTENCE[@NAME='PRIMARY']/TOKEN/@SENTENCE_END) ]

我收到两个节点作为输出:

 <TOKEN BEGIN="17" END="19" SENTENCE_BEGIN="0" SENTENCE_END="156" PROP="C" DOUBLE="YES" />

<TOKEN BEGIN="139" END="141" SENTENCE_BEGIN="0" SENTENCE_END="156" PROP="A" DOUBLE="YES" />

上面的结果不正确,因为我想检查一下:

  1. 和 的SENTENCE_BEGIN SENTENCE_END值相同,并且TOKEN[@DOULBE=YES]SENTENCE[@NAME="PRIMARY"]/TOKEN

  2. 的属性BEGINTOKEN[@DOULBE=YES]小于BEGINSENTENCE[@NAME="PRIMARY"]/TOKEN

结果

 <TOKEN BEGIN="139" END="141" SENTENCE_BEGIN="0" SENTENCE_END="156" PROP="A" DOUBLE="YES" />

不正确,因为BEGIN(139)大于BEGIN具有相同值的标记的相应SENTENCE_BEGIN SENTENCE_END值:

<TOKEN BEGIN="9" END="11" SENTENCE_BEGIN="0" SENTENCE_END="156" />
<TOKEN BEGIN="32" END="37" SENTENCE_BEGIN="0" SENTENCE_END="156" />

如何修改代码行以获得所需的结果?

标签: xpathxslt-1.0

解决方案


由于您已标记您的问题 XSLT 1.0,我将使用 XSLT 而不是纯 XPath。这样你就可以使用xsl:keycurrent()

例子...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="primary_tokens" 
    match="SENTENCE[@NAME='PRIMARY']/TOKEN" 
    use="concat(@SENTENCE_BEGIN,'|',@SENTENCE_END)"/>

  <xsl:template match="/*">
    <xsl:for-each select=".//TOKEN[@DOUBLE='YES'][key('primary_tokens',concat(@SENTENCE_BEGIN,'|',@SENTENCE_END))]">
      <xsl:if test="key('primary_tokens',concat(@SENTENCE_BEGIN,'|',@SENTENCE_END))[@BEGIN > current()/@BEGIN]">
        <xsl:copy-of select="."/>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

小提琴:http: //xsltfiddle.liberty-development.net/gWmuiJ8


推荐阅读