通过使用xslt添加和重新排列节点来重写XML结果树

时间:2015-11-17 12:08:08

标签: xml xslt

我需要重写一组<p><lb>个节点。这是我的初始节点集:

<p>
    text[1] and nodes[1] here
    <pb/>
    text[2] and nodes[2] here
    <pb/>
    text[3] and nodes[3] here
    <pb/>
    [...]
    text[x] and any nodes[x] here
</p>

这就是我需要的:

<p>text[1] and nodes[1] here</p>
<pb/>
<p>text[2] and nodes[2] here</p>
<pb/>
<p>text[3] and nodes[3] here</p>
<pb/>
<p>[...]</p>
<p>text[x] and nodes[x] here</p>

我设法通过将它们放在变量中进行进一步转换来重写第一个和最后一个节点和文本:

<xsl:variable name="textAndNotes_1">
    <p>
         <xsl:copy-of select=" child::node()[not( preceding-sibling::*:pb)
         and not(self::*:pb)]"/>
    </p>
</xsl:variable>

[...]

<xsl:variable name="textAndNotes_x">
    <p>
        <xsl:copy-of select="child::node()[not(following-sibling::*:pb) and  
        not(self::*:pb)]"/>
    </p>
</xsl:variable>

这也适用于第一个和最后一个<pb/>。但我与内部<p>...</p>和内部<pb/>堆叠,我不确定这是正确的方法。我一直在寻找几个小时而没有找到答案。有什么帮助吗?

一切顺利,特里斯坦

2 个答案:

答案 0 :(得分:0)

以下样式表:

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"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="p">
    <xsl:for-each-group select="node()" group-starting-with="pb">
        <p>
            <xsl:apply-templates select="current-group()[not(self::pb)]" />
        </p>    
    </xsl:for-each-group>
</xsl:template>

</xsl:stylesheet>

应用于以下测试输入时:

<强> XML

<root>
    <p>
        text[1] and nodes[1] here
        <pb/>
        text[2] and nodes[2] here
        <pb/>
        text[3] and nodes[3] here
        <pb/>
        [...]
        text[x] and any nodes[x] here
    </p>
</root> 

将返回:

<强>结果

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <p>
        text[1] and nodes[1] here
        </p>
   <p>
        text[2] and nodes[2] here
        </p>
   <p>
        text[3] and nodes[3] here
        </p>
   <p>
        [...]
        text[x] and any nodes[x] here
    </p>
</root>

请注意,这假设所有<pb/>分隔符都是p的直接子代。

答案 1 :(得分:0)

对于我的知识级别的XSL,它出来了一个复杂的XSL,但它在这里:

<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:strip-space elements="*"/>

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

<xsl:template match="p">
    <!--Counts the number of groups and calls the iterator template-->
    <xsl:call-template name="print-all-groups"><xsl:with-param name="numgroups" select="count(pb)"/><xsl:with-param name="index" select="0"/></xsl:call-template>
</xsl:template>

<xsl:template name="print-all-groups">
    <!--Iterates the child groups of P: from the index-th to the numgroups-th-->
    <xsl:param name="numgroups"></xsl:param>
    <xsl:param name="index"></xsl:param>
    <xsl:call-template name="print-group"><xsl:with-param name="index" select="$index"></xsl:with-param></xsl:call-template>
    <xsl:if test="$index &lt; $numgroups">
        <xsl:call-template name="print-all-groups"><xsl:with-param name="numgroups" select="$numgroups"/><xsl:with-param name="index" select="1+$index"/></xsl:call-template>
    </xsl:if>   
</xsl:template>

<xsl:template name="print-group">
    <!--Selects the first node after the index-th group and processes it (applies the 'group-item' templates)-->
    <xsl:param name="index"></xsl:param>
    <xsl:if test="$index=0">
        <p><xsl:apply-templates select="(text()|*)[1]" mode="group-item"></xsl:apply-templates></p>
    </xsl:if>
    <xsl:if test="not($index=0)">
        <p><xsl:apply-templates select="(pb[$index]/following-sibling::text()|pb[$index]/following-sibling::*)[1]" mode="group-item"></xsl:apply-templates></p>
    </xsl:if>
    <pb/>
</xsl:template>

<xsl:template match="*" mode="group-item">
    <!--Copies the current node and iterates to the following sibling until a PB is found-->
    <xsl:if test="name(.) !='pb'">
        <xsl:copy-of select="current()"/>
        <xsl:apply-templates select="(following-sibling::text()|following-sibling::*)[1]" mode="group-item"></xsl:apply-templates>
    </xsl:if>
</xsl:template>

<xsl:template match="text()" mode="group-item">
    <!--Copies the current node and iterates to the following sibling-->
    <xsl:copy-of select="current()"/>
    <xsl:apply-templates select="(following-sibling::text()|following-sibling::*)[1]" mode="group-item"></xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

唯一的'技巧'是始终在每个组之后打印<pb>节点。这是错的吗?

我用这个XML测试过它:

<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
    <p>
        text1<month>january</month><day>monday</day>
        <pb/>
        text2<month>february</month><day>tuesday</day>
        <pb/>
        text3<month>march</month><day>wednesday</day>
    </p>
</root>

...它产生了这个输出:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<p>
        text1<month>january</month>
<day>monday</day>
</p>
<pb/>
<p>
        text2<month>february</month>
<day>tuesday</day>
</p>
<pb/>
<p>
        text3<month>march</month>
<day>wednesday</day>
</p>
<pb/>
</root>