关于选择节点集的xpath问题

时间:2009-02-25 18:49:59

标签: xslt xpath

以下是我的源xml文档的简化版本:

<eml> 
<additionalMetadata>
    <describes>sbclter.380</describes>
    <access authSystem="knb" order="denyFirst">
      <allow>
        <principal>public</principal>
        <permission>all</permission>
      </allow>
    </access>
  </additionalMetadata>

  <additionalMetadata>
    <describes>sbclter.415</describes>
    <describes>sbclter.380</describes>
      <access authSystem="knb" order="allowFirst">
        <allow>
          <principal>public</principal>
          <permission>all</permission>
        </allow>
      </access>
  </additionalMetadata>

  <additionalMetadata>
        <describes>sbclter.415</describes>
        <access authSystem="knb" order="allowFirst">
            <allow>
              <principal>public</principal>
              <permission>all</permission>
            </allow>
          </access>
    </additionalMetadata>
 <eml>

我想选择元素“describe”的节点集 - 它的值显示在多个addtionalMetadata块中,其“access”兄弟具有不同的顺序:“denyFirst”和“allowFirst”。

在上面的例子中,值为sbclter.380的“describe”就是这种情况。由于它显示在两个额外的元数据块中,第一个在访问兄弟中具有“denyFirst”,但第二个在访问兄弟中具有“allowFirst”。 sbclter.415不会是这样的。由于它显示在两个额外的元数据块中,但两个访问兄弟在属性“order”处具有相同的值“allowFirst”。

转型后,我想得到:

<eml> 
    <additionalMetadata>
        <describes>sbclter.380</describes>
        <access authSystem="knb" order="denyFirst">
          <allow>
            <principal>public</principal>
            <permission>all</permission>
          </allow>
        </access>
      </additionalMetadata>

      <additionalMetadata>
        <describes>sbclter.380</describes>
          <access authSystem="knb" order="allowFirst">
            <allow>
              <principal>public</principal>
              <permission>all</permission>
            </allow>
          </access>
      </additionalMetadata>

      <additionalMetadata>
            <access authSystem="knb" order="allowFirst">
                <allow>
                  <principal>public</principal>
                  <permission>all</permission>
                </allow>
              </access>
        </additionalMetadata>
     <eml>

这是我的节点:

   <xsl:for-each select="/*/*">
        <xsl:choose>
           <xsl:when test="name()='additionalMetadata'">
            <xsl:call-template name="handle-describe-access-in-additional-metadata">
                <xsl:with-param name="describes-list" select="./describes[//additionalMetadata[describes = . and access[@order='allowFirst']] and //additionalMetadata[describes = . and access[@order='denyFirst']]]"
          ></xsl:with-param>
              ></xsl:with-param>
            </xsl:call-template>
          </xsl:when>
        </xsl:choose>
      </xsl:for-each>

然而,它不起作用。 “xsl:with-param”中的xpath没有任何东西 - 没有sbclter.415 sbclter.380。你有什么建议吗?非常感谢你!

注意:这是代码的简化版本。

3 个答案:

答案 0 :(得分:1)

这是一个产生想要结果的转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>
<!--                                                --> 
 <xsl:key name="kDescrByVal" match="describes"
  use="."/>
<!--                                                --> 
    <xsl:template match="node()|@*" name="identity">
      <xsl:copy>
         <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    </xsl:template>
<!--                                                --> 
    <xsl:template match="describes">
      <xsl:if test=
       "count(key('kDescrByVal', .)) > 1
       and
        following-sibling::access/@order
       !=
        key('kDescrByVal', .)/following-sibling::access/@order
       ">
       <xsl:call-template name="identity"/>
      </xsl:if>
    </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档(更正为格式良好):

<eml>
    <additionalMetadata>
        <describes>sbclter.380</describes>
        <access authSystem="knb" order="denyFirst">
            <allow>
                <principal>public</principal>
                <permission>all</permission>
            </allow>
        </access>
    </additionalMetadata>
    <additionalMetadata>
        <describes>sbclter.415</describes>
        <describes>sbclter.380</describes>
        <access authSystem="knb" order="allowFirst">
            <allow>
                <principal>public</principal>
                <permission>all</permission>
            </allow>
        </access>
    </additionalMetadata>
    <additionalMetadata>
        <describes>sbclter.415</describes>
        <access authSystem="knb" order="allowFirst">
            <allow>
                <principal>public</principal>
                <permission>all</permission>
            </allow>
        </access>
    </additionalMetadata>
</eml>

生成了想要的结果

<eml>
    <additionalMetadata>
        <describes>sbclter.380</describes>
        <access authSystem="knb" order="denyFirst">
            <allow>
                <principal>public</principal>
                <permission>all</permission>
            </allow>
        </access>
    </additionalMetadata>
    <additionalMetadata>

        <describes>sbclter.380</describes>
        <access authSystem="knb" order="allowFirst">
            <allow>
                <principal>public</principal>
                <permission>all</permission>
            </allow>
        </access>
    </additionalMetadata>
    <additionalMetadata>

        <access authSystem="knb" order="allowFirst">
            <allow>
                <principal>public</principal>
                <permission>all</permission>
            </allow>
        </access>
    </additionalMetadata>
</eml>

请注意使用

  1. 键。

  2. Xpath "!="运算符。

答案 1 :(得分:0)

我会尝试创建当前描述节点的变量并使用它而不是在XPath子表达式中引用.

因为,例如,在[//additionalMetadata[describes = .语句中,.引用了additionalMetadata节点,而不是描述节点。

答案 2 :(得分:0)

在我对你的回答的评论中阐述我所说的内容,这是一个展示我的意思的例子:

将此XML文件用作源,

<Header>
  <thing>
    <child>5</child>
  </thing>
  <thing>
    <child>6</child>
  </thing>
  <thing>
    <child>7</child>
  </thing>
  <thang>
    <children>5</children>
  </thang>
</Header>

使用此XSLT文件:

<xsl:template match="/Header">
    <xsl:value-of select="./thing[//thang[children = ./child]]"/>
</xsl:template>

如果在此示例中.引用thing,则输出将为5,但从那以后。是指thang,没有输出。如果有一个包含thing的变量,那么它将起作用:

  <xsl:template match="/Header">
    <xsl:variable name="thing" select="./thing"/>
    <xsl:value-of select="./thing[//thang[children = $thing/child]]"/>
  </xsl:template>

你处于同样的境地。您的.引用的内容不是您认为的内容。