将平面XML转换为分层XML

时间:2013-11-19 11:09:57

标签: xml xslt hierarchical flat

我正在尝试创建一个XSLT来转换以下XML结构

<?xml version="1.0"?>
<rows>
    <row>       
                <e1>A1</e1>
                <l2>B1-01</l2>
                <q2>C1-1-1</q2>
                <n2>D111</n2>
    </row>
    <row>       
                <e1>A1</e1>             
                <l2>B1-01</l2>
                <q2>C1-1-2</q2>
                <n2>D112</n2>
    </row>
    <row>       
                <e1>A1</e1>             
                <l2>B1-02</l2>
                <q2>C1-2-1</q2>
                <n2>D121</n2>
    </row>
    <row>       
                <e1>A1</e1>             
                <l2>B1-02</l2>
                <q2>C1-2-2</q2>
                <n2>D122</n2>
    </row>  
    <row>       
                <e1>A2</e1>             
                <l2>B2-01</l2>
                <q2>C2-1-1</q2>
                <n2>D211</n2>
    </row>
    <row>       
                <e1>A2</e1>             
                <l2>B2-01</l2>
                <q2>C2-1-2</q2>
                <n2>D212</n2>
    </row>
    <row>       
                <e1>A2</e1>             
                <l2>B2-02</l2>
                <q2>C2-2-1</q2>
                <n2>D221</n2>
    </row>
    <row>       
                <e1>A2</e1>             
                <l2>B2-02</l2>
                <q2>C2-2-2</q2>
                <n2>D222</n2>
    </row>      
</rows>

进入这个

<?xml version="1.0"?>
<e1s xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <e1>A1</e1>
    <l2s>
        <l2>B1-01</l2>
        <q2s>
            <q2>D111</q2>
            <q2>D112</q2>
        </q2s>
        <l2>B1-02</l2>
        <q2s>
            <q2>D121</q2>
            <q2>D122</q2>
        </q2s>
    </l2s>
    <e1>A2</e1>
    <l2s>
        <l2>B2-01</l2>
        <q2s>
            <q2>D211</q2>
            <q2>D212</q2>
        </q2s>
        <l2>B2-02</l2>
        <q2s>
            <q2>D221</q2>
            <q2>D222</q2>
        </q2s>
    </l2s>
</e1s>

我尝试了以下XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:output method="xml" version="1.0" indent="yes" omit-xml-declaration="no"/>
    <xsl:key name="ke1" match="row" use="e1" />
    <xsl:key name="kl2" match="row" use="concat(e1,'#',l2)" />  
    <xsl:template match="rows"> 
    <e1s>    
    <xsl:for-each select="row[generate-id() = generate-id(key('ke1', e1)[1])]">     
        <e1>
        <xsl:value-of select="e1"/>
        </e1>
        <l2s>       
        <xsl:for-each select="../row[generate-id() = generate-id(key('kl2', concat(e1,'#',l2))[1])]">
            <l2>
            <xsl:value-of select="l2"/>
            </l2>
            <q2s>               
                <xsl:for-each select="key('kl2', concat(e1,'#',l2))">
                    <q2>
                        <xsl:value-of select="n2" />
                    </q2>
                </xsl:for-each>
            </q2s>          
        </xsl:for-each>
        </l2s>      
    </xsl:for-each>
    </e1s>
    </xsl:template>
</xsl:stylesheet>

但输出不好,因为它在A1元素中包含“B2” - 反之亦然。虽然我现在试了两天,但似乎我没有把钥匙弄好。有人可以帮帮我吗?

1 个答案:

答案 0 :(得分:1)

您的关键定义很好,问题出在您的第二级for-each

<xsl:for-each select="../row[generate-id() = generate-id(key('kl2', concat(e1,'#',l2))[1])]">

每次围绕外部for-each,此选择将​​为e1#l2的所有值处理所有 e1组。您需要在此处进行过滤,以便您只选择与当前 e1匹配的行,而不是从所有行中选择:

<xsl:for-each select="key('ke1', e1)[generate-id() = generate-id(key('kl2', concat(e1,'#',l2))[1])]">

通过此更改,我得到了正确的结果。