使用xslt移动xml元素

时间:2017-02-11 00:56:19

标签: xml xslt

我有一个像这样的xml文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <i xmlns="http://stuff.com" >
        <v>
            <iNumber>0118</iNumber>
            <s>1</s>
            <a>24</a>
            <p>2175</p>
            <p>2175</p>
            <p>4534</p>
        </v>
    </i>

但我需要将导出看起来像这样。

    <?xml version="1.0" encoding="UTF-8"?>
    <i xmlns="http://stuff.com" >
        <v>
            <iNumber>0118</iNumber>
            <s>1</s>
            <a>24</a>
            <p>2175</p>
        </v>
        <v>
            <iNumber>0118</iNumber>
            <s>1</s>
            <a>24</a>
            <p>2175</p>
        </v>
            <iNumber>0118</iNumber>
            <s>1</s>
            <a>24</a>
            <p>4534</p>
        </v>
    </i>

我是xslt的新手,所以我想帮助转换这个xml

这是我的尝试:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
                xmlns:stuff="http://stuff.com" exclude-result-prefixes="stuff">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*"/>

 <xsl:template match="stuff:v">
    <xsl:copy>
        <xsl:copy-of select="ancestor::stuff:v/stuff:p"/>
    <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

 </xsl:stylesheet>

我已更新我的问题以显示我的尝试

2 个答案:

答案 0 :(得分:1)

这应该可以解决问题:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:stuff="http://stuff.com" exclude-result-prefixes="stuff">

    <xsl:output version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />

    <xsl:strip-space elements="*"/>

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

    <xsl:template match="stuff:v">
        <xsl:for-each select="stuff:p">
            <xsl:apply-templates select="ancestor::stuff:v" mode="copying">
                <xsl:with-param name="pId" select="generate-id()" /> 
            </xsl:apply-templates>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="stuff:v" mode="copying">
        <xsl:param name="pId" />
        <xsl:copy>
            <xsl:apply-templates select="@*|node()">
                <xsl:with-param name="pId" select="$pId" /> 
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="stuff:p">
        <xsl:param name="pId"/>
        <xsl:if test="generate-id() = $pId">
            <xsl:copy-of select="." />
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

一些解释。匹配node()|@*的第一个模板只是默认复制内容。

匹配stuff:v的第二个模板将在遇到stuff:v元素时接管。它会迭代所有东西:p元素,并且每个元素都将匹配的模板应用到它的东西:v ancestor。但是,它进入一个名为“复制”的模式,并使用参数pId调用模板,参数stuff:v是p元素的id。 XML中的每个元素都有一些唯一标识它的隐式ID。

这样我们最终会进入下一个模板,该模板也匹配stuff:p,但仅限于“复制”模式。它接受一个pId参数,复制v元素,然后将模板应用于其所有属性和子节点,不再使用“复制”模式但使用pId参数。最后一部分至关重要。

最终模板与{{1}}匹配,但只有在该元素的id与pId参数中给出的id相同时才会复制它。

所以基本上,我们得到的东西:v,遍历每个东西:p in it,对于它们中的每一个它都会转到东西:v再次以不同的模式匹配另一个模板(否则它将无限地递归),并且从那里复制除了东西之外的所有内容:p元素要求它们匹配传递给模板的参数。

答案 1 :(得分:1)

你为什么不这样做:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:stuff="http://stuff.com" 
exclude-result-prefixes="stuff">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/stuff:i">
    <i xmlns="http://stuff.com">
        <xsl:for-each select="stuff:v/stuff:p">
            <v>
                <xsl:copy-of select="../*[not(self::stuff:p)]"/>
                <xsl:copy-of select="."/>
            </v>
        </xsl:for-each>
    </i>
</xsl:template>

</xsl:stylesheet>