在 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 中创建重复节点的标识模板和优先级的主要内容,如果未能解决你的问题,请参考以下文章

如何在 QT 中创建比主线程高优先级的线程

在 C++ 中创建一个包含不同类型事件的最小优先级队列

Java 中的优先级队列,用于跟踪每个节点的位置

根据优先级在pandas数据帧中创建二进制列

实体框架核心关系问题(代码优先) - 重复列

检查表是不是已在代码优先方法中创建