在 XSL 中创建重复节点的标识模板和优先级
Posted
技术标签:
【中文标题】在 XSL 中创建重复节点的标识模板和优先级【英文标题】:Identity template and priority creating duplicate nodes in XSL 【发布时间】:2019-10-18 11:45:46 【问题描述】:所以我有以下 XML 输入:
<parent>
<para> text 1 <NodeTypeA id="1">element1</NodeTypeA> text2 <Xref ref="1"/> text3</para>
<para>text 4</para>
<para><NodeTypeA id="2">elt2</NodeTypeA></para>
<para>text5 <Xref red="2"/>text6 <Xref ref="3"/>text7</para>
</parent>
我正在尝试提取外部参照节点并将 para 节点一分为二,感谢this answer,这很有效。但是,在我的 XSL 代码中,我需要有一个身份模板,并且在我的模板中有一些优先级。
这是我的完整代码:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="@*|node()" priority="0">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="para[Xref]" priority="1">
<xsl:apply-templates select="node()[1]"/>
</xsl:template>
<xsl:template match="para/node()[not(self::Xref)]" priority="1">
<xsl:param name="group" select="."/>
<xsl:apply-templates select="following-sibling::node()[1]">
<xsl:with-param name="group" select="$group | ."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="para/node()[not(self::Xref) and not(following-sibling::Xref)][last()]" priority="1">
<xsl:param name="group" select="."/>
<para>
<xsl:copy-of select="$group | ."/>
</para>
</xsl:template>
<xsl:template match="para/Xref" priority="1">
<xsl:param name="group"/>
<xsl:if test="$group">
<para>
<xsl:copy-of select="$group"/>
</para>
</xsl:if>
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
</xsl:stylesheet>
问题是不包含外部参照节点的 para 节点在我的输出中加倍,而那些包含外部参照节点的节点被转换得很好。这是我得到的 XML 输出:
<?xml version="1.0"?>
<parent>
<para> text 1 <NodeTypeA id="1">element1</NodeTypeA> text2 </para>
<Xref ref="1" />
<para> text3</para>
<para><para>text 4</para></para>
<para><para><NodeTypeA id="2">elt2</NodeTypeA></para></para>
<para>text5 </para>
<Xref red="2" />
<para>text6 </para>
<Xref ref="3" />
<para>text7</para>
</parent>
为什么添加身份模板和某些优先级会破坏此问题,我该如何解决?
PS:我正在使用 XSLT 1
【问题讨论】:
【参考方案1】:如果我正确理解了问题——描述相当混乱,
这是一种解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPrecedingXref" match="node()[not(self::Xref)]"
use="generate-id(following-sibling::Xref[1])"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="para[Xref]">
<xsl:apply-templates select="Xref"/>
<para>
<xsl:apply-templates
select="node()[not(self::Xref) and not(following-sibling::Xref)]"/>
</para>
</xsl:template>
<xsl:template match="para/Xref">
<para>
<xsl:apply-templates select="key('kPrecedingXref', generate-id())"/>
</para>
<xsl:call-template name="identity"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<parent>
<para> text 1 <NodeTypeA id="1">element1</NodeTypeA> text2 <Xref ref="1"/> text3</para>
<para>text 4</para>
<para><NodeTypeA id="2">elt2</NodeTypeA></para>
<para>text5 <Xref red="2"/>text6 <Xref ref="3"/>text7</para>
</parent>
产生了想要的正确结果:
<parent>
<para> text 1 <NodeTypeA id="1">element1</NodeTypeA> text2 </para>
<Xref ref="1"/>
<para> text3</para>
<para>text 4</para>
<para>
<NodeTypeA id="2">elt2</NodeTypeA>
</para>
<para>text5 </para>
<Xref red="2"/>
<para>text6 </para>
<Xref ref="3"/>
<para>text7</para>
</parent>
【讨论】:
刚刚试了一下,效果很好!!谢谢 !当外部参照节点后没有任何内容时,我仍然必须添加一个简单的 if 测试,但一切正常!以上是关于在 XSL 中创建重复节点的标识模板和优先级的主要内容,如果未能解决你的问题,请参考以下文章