拆分 XSLT 中的合并单元格

Demerge the merged cell in XSLT

谁能帮我解决下面的 xslt 问题。

<?xml version="1.0" encoding="UTF-8"?>
 <catalog>
<cd>
    <title rowmerge="f">Title 1</title>
    <artist rowmerge="f">sample 1</artist>
    <price rowmerge="T">1</price>
    <year >1985</year>
</cd>
<cd>
    <title rowmerge="F">Title 2</title>
    <artist rowmerge="F">Sample 2</artist>
    <price rowmerge="T"></price>
    <year>1988</year>
</cd>
<cd>
    <title rowmerge="F">Title 3</title>
    <artist rowmerge="F">Sample 3</artist>
    <price rowmerge="F">3</price>
    <year>1988</year>
</cd>
<cd>
    <title rowmerge="T">Title 4</title>
    <artist rowmerge="F">sample 4</artist>
    <price rowmerge="T">4</price>
    <year >1985</year>
</cd>
<cd>
    <title rowmerge="T"></title>
    <artist rowmerge="F">Sample 5</artist>
    <price rowmerge="T"></price>
    <year>1988</year>
</cd>
</catalog>

预期输出:

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<cd>
    <title rowmerge="f">Title 1</title>
    <artist rowmerge="f">sample 1</artist>
    <price rowmerge="f">1</price>
    <year >1985</year>
</cd>
<cd>
    <title rowmerge="F">Title 2</title>
    <artist rowmerge="F">Sample 2</artist>
    <price rowmerge="f">1</price>
    <year>1988</year>
</cd>
<cd>
    <title rowmerge="F">Title 3</title>
    <artist rowmerge="F">Sample 3</artist>
    <price rowmerge="F">3</price>
    <year>1988</year>
</cd>
<cd>
    <title rowmerge="F">Title 4</title>
    <artist rowmerge="F">sample 4</artist>
    <price rowmerge="F">4</price>
    <year >1985</year>
</cd>
<cd>
    <title rowmerge="F">Title 4</title>
    <artist rowmerge="F">Sample 5</artist>
    <price rowmerge="F">4</price>
    <year>1988</year>
</cd>
</catalog>

如果任何标签 (title/artist/price) 的第一个 cd 中的 rowmerge 属性是 'T',那么我需要将价格值从第一个 cd 复制到下一个 cd。我是 xslt 的新手。

您首先应该阅读 XSLT Identity Template,它会自行将节点从源文档复制到输出。

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

这意味着您只需要为要转换的节点编写模板即可。现在只考虑 price 元素,您正在尝试修改 price 元素,这些元素的 rowmerge 设置为 "T" 且为空。在这种情况下,您想要从第一个最前面的 'cd' 复制 price。这是这样实现的:

<xsl:template match="price[@rowmerge='T'][not(normalize-space())]">
    <price>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:value-of select="../preceding-sibling::*[1]/price" />
    </price>
</xsl:template> 

因此,它与身份模板非常相似,但它有额外的 xsl:value-of 语句来从前面的节点复制值。或者更确切地说,来自父 cd 元素的前一个节点的 price 值。

当然,您可以为 cd 的每个可能的子元素重复此模板,但这会产生大量重复编码。最好有一个更通用的模板来涵盖所有情况:

<xsl:template match="*[@rowmerge='T'][not(normalize-space())]">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:value-of select="../preceding-sibling::*[1]/*[name() = name(current())]" />
    </xsl:copy>
</xsl:template>

试试这个 XSLT

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

    <xsl:template match="*[@rowmerge='T'][not(normalize-space())]">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <xsl:value-of select="../preceding-sibling::*[1]/*[name() = name(current())]" />
        </xsl:copy>
    </xsl:template>


    <xsl:template match="@rowmerge[. = 'T']">
        <xsl:attribute name="rowmerge">F</xsl:attribute>
    </xsl:template>

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

请注意,还有一个模板可以将 rowmerge 属性的值从 T 转换为 F

编辑:在回答您的评论时,如果您必须回头看一个以上的兄弟姐妹(也就是说,您有两个连续的空元素),请尝试这两个表达式之一

<xsl:value-of select="../preceding-sibling::*[*[name() = name(current())][normalize-space()]][1]/*[name() = name(current())]" />

<xsl:value-of select="(../preceding-sibling::*/*[name() = name(current())][normalize-space()])[last()]" />

编辑 2:如果节点包含的不仅仅是文本,那么要复制所有子元素,您可以使用 xsl:copy-of 而不是 xsl:value-of。例如...

<xsl:copy-of select="../preceding-sibling::*[1]/*[name() = name(current())]/node()" />

注意在末尾使用 node(),以确保只复制子节点,而不是 price(例如)元素本身。