我有以下两个XML案例。
情况1:
<para>Rent is the sum of money paid by the Tenant to the Landlord for the exclusive use of premises. The Landlord and Tenant signs a <page num="4"/>tenancy agreement which has to be stamped with the tax authorities as required under the Stamp Duties Act. The stamping of a tenancy agreement gives it validity but if the tenancy agreement is not stamped that does not mean</para>
情况2:
<para><page num="5"/>The Writ of Distress proceedings is an effective way to recover arrears in rent but regard must be had to the Landlord/Tenant relationship and the effect of publicity of such proceedings to the image of the building amongst other things.</para>
以及下面的XSLT
<xsl:template match="para">
<xsl:apply-templates select="child::node()[(self::page)]"/>
<li class="item">
<div class="para">
<span class="item-num">
<xsl:value-of select="../@num"></xsl:value-of>
</span>
<xsl:apply-templates select="child::node()[not(self::page)]"/>
</div>
</li>
</xsl:template>
<xsl:template match="page">
<xsl:processing-instruction name="pb">
<xsl:text>label='</xsl:text>
<xsl:value-of select="./@num"/>
<xsl:text>'</xsl:text>
<xsl:text>?</xsl:text>
</xsl:processing-instruction>
<a name="{concat('pg_',./@num)}"/>
<xsl:apply-templates/>
</xsl:template>
我要做的是检查page
是否是para
的直接(第一个)孩子,然后先打印该值,然后再进行其余操作。但在这两种情况下,首先打印page
。
在上述案例中,对于case1,page
应该像para
中的任何其他模板一样调用,因为它不是para
的直接子项,而是在case2中,首先必须打印page
,然后调用模板,因为page num="5"
是para
的直接子项。请让我知道如何执行此操作。
演示是here
答案 0 :(得分:5)
我认为您的意思是,当页面是段下的第一个子节点时,您希望执行额外处理。您的 apply-templates 需要看起来像这样
<xsl:apply-templates select="node()[1][self::page]" />
但是,听起来您还想在页面元素上执行其他处理。您可能需要两个匹配页面的模板,但其中一个模板与“模式”相匹配,以区别于正常处理。
像这样称呼
<xsl:apply-templates select="node()[1][self::page]" mode="first"/>
并像这样匹配
<xsl:template match="page" mode="first">
这将包含输出处理指令的代码。
对于页面元素的“正常”处理,只需另一个模板匹配页面而不使用模式
<xsl:template match="page">
<a name="{concat('pg_',./@num)}"/>
<xsl:apply-templates/>
</xsl:template>
试试这个XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="para">
<xsl:apply-templates select="node()[1][self::page]" mode="first"/>
<li class="item">
<div class="para">
<span class="item-num">
<xsl:value-of select="../@num"></xsl:value-of>
</span>
<xsl:apply-templates />
</div>
</li>
</xsl:template>
<xsl:template match="page">
<a name="{concat('pg_',./@num)}"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="page" mode="first">
<xsl:processing-instruction name="pb">
<xsl:text>label='</xsl:text>
<xsl:value-of select="./@num"/>
<xsl:text>'</xsl:text>
</xsl:processing-instruction>
</xsl:template>
</xsl:stylesheet>
编辑:如果您不想同时申请“页面”模板以应用第一个页面元素,请添加以下模板以忽略它
<xsl:template match="page[not(preceding-sibling::node())]" />
请注意,只有在文档中出现<xsl:strip-space elements="*" />
时,才能使用此选项来删除仅限空格的文本节点。或者,你可以写这个
<xsl:template match="page[not(preceding-sibling::node()[not(self::text()) or normalize-space()])]" />
编辑2:你需要额外模板的原因是因为这行
<xsl:apply-templates />
这将查找与当前 para 元素下的所有子元素匹配的模板。因此,对于页面元素,将匹配以下模板
<xsl:template match="page">
但是你说你不希望在这种情况下匹配第一个页面元素。因此,您是一个更“特定”的模板来匹配它。例如
<xsl:template match="page[not(preceding-sibling::node())]" />
此模板与页面元素匹配,没有前一个兄弟;即 para 下的第一个元素。
XSLT具有模板优先级的概念。如果模板匹配具有指定条件的元素,则该模板将始终优先。在这种情况下,特定模板只是忽略页面元素,以确保它不会被输出。
对于其他页面元素,其他模板将正常使用。