【问题标题】:XSLT - adding attribute dynamically in groupingXSLT - 在分组中动态添加属性
【发布时间】:2015-09-18 14:03:52
【问题描述】:

我有一个如下的xml,

<doc>
    <section>
        <p id="main">aa</p>
        <p id="main">bb</p>
        <p id="main">cc</p>
        <p id="para1">dd</p>
        <p id="main">ee</p>
        <p id="main">ff</p>
        <p id="main">gg</p>
        <p id="para2">hh</p>
        <p id="main">ii</p>
        <p id="main">jj</p>
        <p id="para1">xx</p>
        <p id="main">yy</p>
        <p id="main">zz</p>
    </section>
</doc>

我的任务是根据id="para1"id='para2' 属性对上述内容进行分组,并在每个组中添加一个部分。我想要的输出是

<doc>
    <section>
        <p id="main">aa</p>
        <p id="main">bb</p>
        <p id="main">cc</p>
    </section>
    <section  type="First para">
        <p id="para1">dd</p>
        <p id="main">ee</p>
        <p id="main">ff</p>
        <p id="main">gg</p>
    </section>
    <section type="Second para">
        <p id="para2">hh</p>
        <p id="main">ii</p>
        <p id="main">jj</p>
    </section>
    <section  type="First para">
        <p id="para1">xx</p>
        <p id="main">yy</p>
        <p id="main">zz</p>
    </section>
</doc>

执行这个任务的xsl如下,

<xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="section">
        <xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
            <section type="?">
                <xsl:apply-templates select="current-group()"/>
            </section>      
        </xsl:for-each-group>
    </xsl:template>

这个 xsl 可以完成这项工作,但您能否建议一种方法,我如何根据组添加 &lt;section&gt; 节点的 type 属性值?

【问题讨论】:

    标签: xml xslt xslt-2.0


    【解决方案1】:

    以下样式表:

    XSLT 2.0

    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="section">
        <xsl:for-each-group select="p" group-starting-with="p[starts-with(@id, 'para')]">
            <section>
                <xsl:if test="current-group()[1][not(@id='main')]">
                    <xsl:attribute name="type" select="current-group()[1]/@id"/>
                </xsl:if>
                <xsl:apply-templates select="current-group()"/>
            </section>      
        </xsl:for-each-group>
    </xsl:template>
    
    </xsl:stylesheet>
    

    将返回:

    结果

    <?xml version="1.0" encoding="utf-8"?>
    <doc>
        <section>
          <p id="main">aa</p>
          <p id="main">bb</p>
          <p id="main">cc</p>
       </section>
        <section type="para1">
          <p id="para1">dd</p>
          <p id="main">ee</p>
          <p id="main">ff</p>
          <p id="main">gg</p>
       </section>
        <section type="para2">
          <p id="para2">hh</p>
          <p id="main">ii</p>
          <p id="main">jj</p>
       </section>
        <section type="para1">
          <p id="para1">xx</p>
          <p id="main">yy</p>
          <p id="main">zz</p>
       </section>
    </doc>
    

    将“para1”和“para2”分别转换为“First para”和“Second para”可能会更复杂。这将有助于了解所有可能出现的组合。如果它总是采用“paraN”的格式,那么你可以使用:

    <xsl:attribute name="type">
        <xsl:number value="substring-after(current-group()[1]/@id, 'para')" format="Ww" ordinal="yes"/>
        <xsl:text> para</xsl:text>
    </xsl:attribute>
    

    生产:

    <?xml version="1.0" encoding="utf-8"?>
    <doc>
        <section>
          <p id="main">aa</p>
          <p id="main">bb</p>
          <p id="main">cc</p>
       </section>
        <section type="First para">
          <p id="para1">dd</p>
          <p id="main">ee</p>
          <p id="main">ff</p>
          <p id="main">gg</p>
       </section>
        <section type="Second para">
          <p id="para2">hh</p>
          <p id="main">ii</p>
          <p id="main">jj</p>
       </section>
        <section type="First para">
          <p id="para1">xx</p>
          <p id="main">yy</p>
          <p id="main">zz</p>
       </section>
    </doc>
    

    【讨论】:

    • for-each-group 中,上下文节点是每个组中的第一项,因此您可以将&lt;xsl:if test="current-group()[1][not(@id='main')]"&gt; 缩短为&lt;xsl:if test="not(@id='main')"&gt;,将&lt;xsl:attribute name="type" select="current-group()[1]/@id"/&gt; 缩短为&lt;xsl:attribute name="type" select="@id"/&gt;
    • @MartinHonnen 我相信你是正确的,但我无法在规格中找到确认。它只是说 initial itemcontext item 用于排序
    • for-each-group 上的部分定义了“对于每个组,组内按人口顺序排在第一位的项称为组的初始项。”然后稍后说“xsl:for-each-group 元素中包含的序列构造函数按处理顺序为每个组评估一次。......在序列构造函数中,上下文项是相关项的初始项组...”
    • @MartinHonnen 我明白了。如果您现在没有指出它,我永远不会将其理解为您在第一条评论中所说的意思。我将按原样保留我的答案,因为我相信阅读此内容的任何人都会通过关注此讨论受益更多。感谢您的澄清。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-02
    相关资源
    最近更新 更多