2

我一直在寻找答案,并尝试了数百种排列,但没有任何效果。

我正在尝试处理一个简单 XML 文档的所有节点,除了第一个<title>节点。基本上,我正在尝试找到一个 xslt 指令来完成确切的 INVERSE

<xsl:apply-templates select="/topic/title"/>

这是我的源 XML:

<topic>
    <title>Name of the Document</title>
    <p>Document body</p>
    <topic>
        <title>First Document Subtopic</title>
        <p>Body text for first document subtopic</p>
    </topic>
    <p>Body text continued for document</p>
    <topic>
        <title>Second Document Subtopic</title>
        <p>Body text for document subtopic</p>
        <topic>
            <title>First Document Sub-subtopic</title>
            <p>Body text for first document sub-subtopic</p>
        </topic>
    </topic>
    <p>Body text continued a second time for document</p>
</topic>

这是我的 XSLT(我最初认为应该在调用应用模板时使用):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output omit-xml-declaration="yes" encoding="UTF-8" method="xml"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <BOX>
            <TEXTFLOW>
                <xsl:apply-templates select="*[not(/topic/title)]"/>
            </TEXTFLOW>
        </BOX>
    </xsl:template>

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

    <xsl:template match="title">
        <PARA STYLE="Title"/>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="p">
        <PARA STYLE="BodyText"/>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="text()">
        <FORMAT>
            <xsl:value-of select="."/>
        </FORMAT>
    </xsl:template>
</xsl:stylesheet>

这就是我看到的(注意没有第一<title>件事):

<BOX>
    <TEXTFLOW>
        <PARA STYLE="BodyText"/>
        <FORMAT>Document body</FORMAT>
        <PARA STYLE="Title"/>
        <FORMAT>First Document Subtopic</FORMAT>
        <PARA STYLE="BodyText"/>
        <FORMAT>Body text for first document subtopic</FORMAT>
        <PARA STYLE="BodyText"/>
        <FORMAT>Body text continued for document</FORMAT>
        <PARA STYLE="Title"/>
        <FORMAT>Second Document Subtopic</FORMAT>
        <PARA STYLE="BodyText"/>
        <FORMAT>Body text for document subtopic</FORMAT>
        <PARA STYLE="Title"/>
        <FORMAT>First Document Sub-subtopic</FORMAT>
        <PARA STYLE="BodyText"/>
        <FORMAT>Body text for first document sub-subtopic</FORMAT>
        <PARA STYLE="BodyText"/>
        <FORMAT>Body text continued a second time for document</FORMAT>
    </TEXTFLOW>
</BOX>

我可以使用什么选择表达式来完成此操作?

4

2 回答 2

6

就这么简单

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

    <xsl:template match="/">
        <BOX>
            <TEXTFLOW>
                <xsl:apply-templates/>
            </TEXTFLOW>
        </BOX>
    </xsl:template>

    <xsl:template match="/topic/title"/>

    <xsl:template match="title">
        <PARA STYLE="Title"/>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="p">
        <PARA STYLE="BodyText"/>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="text()">
        <FORMAT>
            <xsl:value-of select="."/>
        </FORMAT>
    </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<topic>
    <title>Name of the Document</title>
    <p>Document body</p>
    <topic>
        <title>First Document Subtopic</title>
        <p>Body text for first document subtopic</p>
    </topic>
    <p>Body text continued for document</p>
    <topic>
        <title>Second Document Subtopic</title>
        <p>Body text for document subtopic</p>
        <topic>
            <title>First Document Sub-subtopic</title>
            <p>Body text for first document sub-subtopic</p>
        </topic>
    </topic>
    <p>Body text continued a second time for document</p>
</topic>

产生了想要的正确结果:

<BOX>
   <TEXTFLOW>
      <PARA STYLE="BodyText"/>
      <FORMAT>Document body</FORMAT>
      <PARA STYLE="Title"/>
      <FORMAT>First Document Subtopic</FORMAT>
      <PARA STYLE="BodyText"/>
      <FORMAT>Body text for first document subtopic</FORMAT>
      <PARA STYLE="BodyText"/>
      <FORMAT>Body text continued for document</FORMAT>
      <PARA STYLE="Title"/>
      <FORMAT>Second Document Subtopic</FORMAT>
      <PARA STYLE="BodyText"/>
      <FORMAT>Body text for document subtopic</FORMAT>
      <PARA STYLE="Title"/>
      <FORMAT>First Document Sub-subtopic</FORMAT>
      <PARA STYLE="BodyText"/>
      <FORMAT>Body text for first document sub-subtopic</FORMAT>
      <PARA STYLE="BodyText"/>
      <FORMAT>Body text continued a second time for document</FORMAT>
   </TEXTFLOW>
</BOX>

说明

为了从处理中排除想要的元素,我们使用一个匹配它们并且没有正文的模板:

    <xsl:template match="/topic/title"/>

二、更新

不推荐使用以下替代解决方案,因为它是“拉式”的示例,不像上面的“推式”解决方案那样灵活、优雅和可维护,但是 OP 坚持认为他需要这样的劣质解决方案:

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

    <xsl:template match="/">
      <BOX>
       <TEXTFLOW>
        <xsl:apply-templates
        select="*/*[not(self::title)]"/>
       </TEXTFLOW>
      </BOX>
    </xsl:template>

    <xsl:template match="title">
        <PARA STYLE="Title"/>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="p">
        <PARA STYLE="BodyText"/>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="text()">
        <FORMAT>
            <xsl:value-of select="."/>
        </FORMAT>
    </xsl:template>
</xsl:stylesheet>

当此转换应用于所提供的 XML 文档(如上)时,它会再次产生所需的正确结果

于 2012-12-24T00:13:23.073 回答
3

好吧,你可以在你的根模板中使用这个 XPath:

select=".//*[generate-id() != generate-id(/topic/title)]"

您需要将模板更改为topic

<xsl:template match="topic" />

您遇到的问题是因为您当前的选择仅指定应处理的直接子级 - 从根注释(/)开始,这实际上只是顶级topic元素。上面 XPath 中的.//*指定所有后代而不考虑级别,并且谓词显式排除第一个/topic/title元素。

您需要确保您的topic元素没有处理它们的子元素,因为它们的子元素已经被根模板中的 select 指令处理。

于 2012-12-25T00:51:39.357 回答