是否可以根据xslt 1.0中的元素名称对子节点进行分组?

时间:2014-06-06 21:34:23

标签: xml xslt xslt-1.0

我有以下输入(xml的片段):

<prompt>
    This is a sentence with <b>bold</b>.
    <p>
        This is in a paragraph element.
    </p>
    This is a <i>second</i> <b>sentence</b>.
</prompt>

我有一个匹配pprompt的模板。在该模板中,它将内容包装在<PARAGRAPH>个元素中。

对于上面的示例,所需的输出是:

<PARAGRAPH>
    This is a sentence with bold.
</PARAGRAPH>
<PARAGRAPH>
    This is in a paragraph element.
</PARAGRAPH>
<PARAGRAPH>
    This is a second sentence.
</PARAGRAPH>

是否有某种方法可以根据元素名称将提示内容分解为组?特别是元素名称为非p和p?

的组

我一直在阅读关于XSLT中的Muenchian分组策略,但看不到如何应用或者甚至可能这样做。也许我应该接近另一种方式?

3 个答案:

答案 0 :(得分:4)

  

是否有某种方法可以将提示内容分解为群组   基于元素名称?

这并不是您向我们展示的内容 - 您的论坛基于<p>元素作为文字节点之间的分隔符。

  

我一直在阅读有关XSLT中的Muenchian分组策略但是   无法看到如何申请或者甚至可以这样做。

这是可能的 - 但在这种情况下,它根本不是微不足道的。按照以下几点尝试:

XSLT 1.0

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="group-by-divider" match="prompt/node()[not(self::p)]" use="count(preceding-sibling::p)" />

<xsl:template match="/">
    <root>
        <xsl:apply-templates select="prompt"/>
    </root>
</xsl:template>

<xsl:template match="prompt">
    <xsl:apply-templates mode="group"/>
</xsl:template>

<xsl:template match="node()[not(self::p)][count(. | key('group-by-divider', count(preceding-sibling::p))[1]) = 1]" mode="group">
    <PARAGRAPH>
        <xsl:apply-templates select="key('group-by-divider', count(preceding-sibling::p))"/>
    </PARAGRAPH>
</xsl:template>

<xsl:template match="p" mode="group">
    <PARAGRAPHx>
        <xsl:apply-templates/>
    </PARAGRAPHx>
</xsl:template>

<!-- suppress nodes other than through the key -->
<xsl:template match="node()" mode="group"/>

</xsl:stylesheet>

您可能需要添加一些空白管理以使其更漂亮。

答案 1 :(得分:2)

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="prompt">
<yourRoot>
<xsl:for-each-group select="node()" group-adjacent="name() = 'p'">
<PARAGRAPH>
<xsl:apply-templates select="current-group()"/>
</PARAGRAPH>
</xsl:for-each-group>
</yourRoot>
</xsl:template>

答案 2 :(得分:2)

以下样式表通过应用模板生成由<p>元素分隔的字符串,然后使用递归模板将该字符串拆分为<paragraph>元素。

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

    <xsl:param name="delimiter" select="'|'"/>

    <xsl:template match="prompt">
        <xsl:call-template name="split-to-paragraph">
            <xsl:with-param name="txt">
                <xsl:apply-templates select="node()" />
            </xsl:with-param>
        </xsl:call-template>
    </xsl:template>

    <xsl:template match="prompt/node()">
        <xsl:value-of select="."/>
    </xsl:template>

    <xsl:template match="prompt/p" priority="1">
        <xsl:value-of select="concat($delimiter, . ,$delimiter)"/>
    </xsl:template>

    <xsl:template name="split-to-paragraph">
        <xsl:param name="delimiter" select="$delimiter"/>
        <xsl:param name="txt"/>
        <xsl:choose>
            <xsl:when test="contains($txt, $delimiter)">
                <PARAGRAPH>
                  <xsl:value-of select="normalize-space(
                                         substring-before($txt, $delimiter))"/>
                </PARAGRAPH>
                <xsl:call-template name="split-to-paragraph">
                   <xsl:with-param name="delimiter" select="$delimiter"/>
                   <xsl:with-param name="txt" 
                                   select="substring-after($txt, $delimiter)"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <PARAGRAPH>
                    <xsl:value-of select="normalize-space($txt)"/>
                </PARAGRAPH>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>