模式输出中的XSLT模板包含应该在其他模式下匹配的元素

时间:2017-01-08 22:06:33

标签: xml templates xslt

我想处理一些节点并再次处理这些节点的子集,特别是那些'n'祖先有一个直接子'x'的节点。

尽可能简化XML:

    <root>
        <s>
        </s>
        <s>
            <n>
                <w a="Hello"/>
                <n>
                    <x/>
                    <w a="he said"/>
                </n>
            </n>
            <n>
                <w a="how are you"/>
            </n>
        <n>
        </n>
        <n>
            <w a="she answered"/>
            <n>
                <n>
                    <x/>
                    <w a="friendly"/>
                </n>
            </n>
        </n>
    </s>
</root>

由于我必须两次处理一些w节点,所以我决定使用模式。我有两种模式(为了可读性,名为'fromone','fromtwo'在这里)匹配'a-attribute',并且还尝试了仅使用一种模式的各种组合,添加了没有模式的空模板,但结果保持不变。

XSLT的相关部分,也简化了,原始模板大多与条件匹配(除了具有模式的模板):

<xsl:template match="root/s">
    <output>
        <one>
            <xsl:apply-templates select="descendant::w"/>
        </one>
        <x>
            <xsl:apply-templates select="n"/>
        </x>
    </output>
</xsl:template>

<xsl:template match="n[x]">
    <xsl:apply-templates select="descendant::w/@a" mode="fromtwo"/>
</xsl:template>

<xsl:template match="w">
    <xsl:apply-templates select="@a" mode="fromone"/>
</xsl:template>

<xsl:template match="@a" mode="fromtwo">
    <fromtwo>
        <xsl:value-of select="."/>
    </fromtwo>
</xsl:template>

<xsl:template match="@a" mode="fromone">
    <fromone>
        <xsl:value-of select="."/>
    </fromone>
</xsl:template>

我希望输出看起来像这样:

<root>
   <output>
      <one>
         <fromone>Hello</fromone>
         <fromone>he said</fromone>
         <fromone>how are you</fromone>
         <fromone>she answered</fromone>
         <fromone>friendly</fromone>
      </one>
      <x>
         <fromtwo>he said</fromtwo>
         <fromtwo>friendly</fromtwo>
      </x>
   </output>
</root>

但是在实际结果中,节点x包含我希望仅匹配来自另一个模板调用的元素到'fromone':

<x>
     <fromone>Hello</fromone>
     <fromtwo>he said</fromtwo>
     <fromone>how are you</fromone>
     <fromone>she answered</fromone>
     <fromtwo>friendly</fromtwo>
  </x>

由于这是我从我尝试的所有XSLT处理器得到的结果,我假设我的模板结构有错误。即使在阅读了有关模式问题的其他帖子之后,我也无法接近解决方案或在XSLT中找到我的错误。

我犯了什么错误?

为什么结果具有两个模板的混合输出而不是仅显示'fromtwo'的输出?

2 个答案:

答案 0 :(得分:0)

  

我犯了什么错误?

当你这样做时:

   <x>
        <xsl:apply-templates select="n"/>
    </x>

您正在将模板应用于所有 n元素。与匹配n的模板不匹配的n[x]元素将由默认built in template处理:

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

即。它将递归地将模板应用于后代,直到它到达w元素 - 您有自定义模板:

<xsl:template match="w">
    <xsl:apply-templates select="@a" mode="fromone"/>
</xsl:template>

为什么你不能简单地做到:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="root">
    <output>
        <one>
            <xsl:apply-templates select=".//w"/>
        </one>
        <x>
            <xsl:apply-templates select=".//n[x]//w" mode="fromtwo"/>
        </x>
    </output>
</xsl:template>

<xsl:template match="w">
    <fromone>
        <xsl:value-of select="@a"/>
    </fromone>
</xsl:template>

<xsl:template match="w" mode="fromtwo">
    <fromtwo>
        <xsl:value-of select="@a"/>
    </fromtwo>
</xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

这是一个默认模板的问题,它捕获每个n - 元素而没有x - 子元素。如果您在<xsl:apply-templates select="n"/> - 节点的上下文中应用s,则s的任何直接后继者都不会拥有x - 子节点,这样您的模板{{ 1}}永远不会匹配。由于没有其他模板匹配,默认模板就会到位并应用每个没有模式的子节点。

所以我添加了一个模板来处理所有n[x] - 没有n的节点 - 子元素:

x

应用于上面的示例,它会产生以下输出:

<xsl:template match="n[not(x)]">
    <xsl:apply-templates select="n"/>
</xsl:template>