1

如果我运行以下 XSLT 代码:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kValueByVal" match="variable_name/@value"
  use="."/>

 <xsl:template match="assessment">
  <xsl:for-each select="
   /*/*/variable/attributes/variable_name/@value
             [generate-id()
             =
              generate-id(key('kValueByVal', .)[1])
             ]
   ">
     <xsl:value-of select=
     "concat(., ' ', count(key('kValueByVal', .)), '&#xA;')"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

在以下 XML 上:

<assessment>
    <variables>
        <variable>
            <attributes>
                <variable_name value="FRED"/>
            </attributes>
        </variable>
    </variables>
    <variables>
        <variable>
            <attributes>
                <variable_name value="MORTIMER"/>
            </attributes>
        </variable>
    </variables>
    <variables>
        <variable>
            <attributes>
                <variable_name value="FRED"/>
            </attributes>
        </variable>
    </variables>
</assessment>

我得到了想要的输出:

FRED 2
MORTIMER 1

(如果您愿意,请参阅我的原始问题以获取更多信息。)

但是,如果我在此输入上运行它:

<ExamStore>
    <assessment>
        <variables>
            <variable>
                <attributes>
                    <variable_name value="FRED"/>
                </attributes>
            </variable>
        </variables>
        <variables>
            <variable>
                <attributes>
                    <variable_name value="MORTIMER"/>
                </attributes>
            </variable>
        </variables>
        <variables>
            <variable>
                <attributes>
                    <variable_name value="FRED"/>
                </attributes>
            </variable>
        </variables>
    </assessment>
</ExamStore>

我什么都得不到。(请注意,我只是将原始输入包装在一个 ExamStore 标记中。)我期待并希望得到相同的输出。

我为什么不呢?如何更改原始 XSLT 代码以获得相同的输出?

4

3 回答 3

1

好吧,您选择的 xpath/*/*/variable/attributes/variable_name/...不再正确,因为您在节点树中添加了另一个更高的节点。

如果你想拥有真正的独立性,你需要使用类似的东西:

//variable/attributes/variable_name/...

...(不是开头的双斜线)但这相当危险,因为它会捕捉到该结构的所有出现 - 一定要确保这就是你的意思。

否则,只需在您的 xpath 前面加上另一个/*

于 2010-07-15T15:00:02.560 回答
1

当您在 XML 文档中引入另一个级别时,这搞砸了原始解决方案中使用的绝对 XPath 表达式(完全按照您的原始 XML 文件定制)。

因此,为了使 XPath 表达式在新情况下工作,只需执行以下操作:

替换

/*/*/variable/attributes/variable_name/@value 

/*/*/*/variable/attributes/variable_name/@value

现在你又得到了想要的整洁的结果:

FRED 2
MORTIMER 1

我永远不会给你一个“独立”的解决方案,因为你没有提供任何关于你想要应用转换的可能 XML 文档集的属性/保证/约束。

在您使用的原始问题中:

.//variables/variable/attributes/variable_name

关闭assessment,

这就是我在解决方案中使用绝对 XPath 表达式的原因。不能保证在另一个 XML 文档中某些variable_name元素不会存在,因此它们的祖先链不存在variables/variable/attributes。如果是这种情况,这意味着您可能对这些“不规则”variable_name元素的值不感兴趣。

教训是,在定义问题时不应该太具体,然后想要通用的解决方案。:)

于 2010-07-16T02:55:58.000 回答
0

对于真正的结构独立性,您应该使用:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kValueByVal" match="variable_name/@value"
  use="."/>

 <xsl:template match="variable_name[@value
             [generate-id()
             =
              generate-id(key('kValueByVal', .)[1])
             ]]">
     <xsl:value-of select=
     "concat(@value, ' ', count(key('kValueByVal', @value)), '&#xA;')"/>
 </xsl:template>
</xsl:stylesheet>

第一个输入的结果:

FRED 2
MORTIMER 1

第二个输入的结果:

FRED 2
MORTIMER 1

注意:永远不要//用作第一个 XPath 运算符。

于 2010-07-15T15:15:26.387 回答