使用XSLT对XML进行排序,同时保留多个注释

时间:2010-11-15 08:24:37

标签: xml xslt

我正在尝试使用XSLT对XML文档进行排序,并希望保留这些注释。到目前为止一直很好,因为这个问题已经有了一些答案(见相关......)。 但是!这些(优秀的)答案都没有涉及到这样的XML:

<xml>
    <beatles>
        <!-- comment(1): john is actually my favourite -->
        <!-- comment(2): John died tragically in 1980 -->
        <beatle name="John"/>

        <beatle name="Ringo"/>

        <beatle name="George"/>

        <!-- comment(1): Paul still does live concerts to this day -->
        <!-- comment(2): contrary to common folklore, Paul is NOT dead! -->
        <beatle name="Paul"/>
    </beatles>
</xml>

现在发生了什么?我想通过名字对甲壳虫乐队(上帝保佑他们)进行排序,并保留每个甲壳虫乐队的所有评论,以便得到这个结果:

<xml>
    <beatles>
        <beatle name="George"/>

        <!-- comment(1): john is actually my favourite -->
        <!-- comment(2): John died tragically in 1980 -->
        <beatle name="John"/>

        <!-- comment(1): Paul still does live concerts to this day -->
        <!-- comment(2): contrary to common folklore, Paul is NOT dead! -->
        <beatle name="Paul"/>

        <beatle name="Ringo"/>
    </beatles>
</xml>

好老前兄弟::评论()[1] 在这里不起作用。在常规代码中,我只对所有前面的注释执行反向循环,并在我点击非注释节点时停止;但众所周知,XSLT的 for-each 无法转义。

有什么想法吗?

TIA!

DF。

2 个答案:

答案 0 :(得分:1)

我认为这可以通过一个键来实现,该键列出给定'beatle'元素的所有注释。

<xsl:key name="comments" match="comment()" use="following-sibling::beatle[1]/@name" />

因此,对于每个评论,它都是由第一个连续的beatle元素索引。

然后您可以按如下方式使用此列表来列出任何beatle元素的所有注释。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml"/>

   <xsl:key name="comments" match="comment()" use="following-sibling::beatle[1]/@name" />

   <xsl:template match="/xml/beatles">
      <beatles>
         <xsl:for-each select="beatle">
            <xsl:sort select="@name" />

            <!-- Loop through all comments for the beatle element -->
            <xsl:for-each select="key('comments', @name)">
               <xsl:comment>
                  <xsl:value-of select="." />
               </xsl:comment>
            </xsl:for-each>

            <!-- Copy the beatle element -->
            <xsl:copy>
               <xsl:copy-of select="@*" />
            </xsl:copy>
         </xsl:for-each>
      </beatles>
   </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

复制相应的beatle节点时,您也应该应用其注释。这就是你需要做的。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="beatles">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="beatle">
                <xsl:sort select="@name" data-type="text"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="beatle">
        <xsl:variable name="current" select="."/>
        <xsl:apply-templates
                select="preceding-sibling::comment()[generate-id(following-sibling::beatle[1]) = generate-id($current)]"/>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>


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

输出:

<?xml version="1.0" encoding="windows-1251"?>
<xml>
    <beatles>
        <beatle name="George"/>
        <!-- comment(1): john is actually my favourite -->
        <!-- comment(2): John died tragically in 1980 -->
        <beatle name="John"/>
        <!-- comment(1): Paul still does live concerts to this day -->
        <!-- comment(2): contrary to common folklore, Paul is NOT dead! -->
        <beatle name="Paul"/>
        <beatle name="Ringo"/>
    </beatles>
</xml>