简体   繁体   English

使用xslt移动xml元素

[英]Move xml element with xslt

I have a xml file like this: 我有一个这样的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>

But I need the export to look like this. 但是我需要导出看起来像这样。

    <?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>

I am new to xslt so I would like some help with transforming this xml please 我是xslt的新手,所以我需要一些有关转换此xml的帮助

Here's my attempt: 这是我的尝试:

<?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>

I've updated my question to show my attempt 我已经更新了问题以显示我的尝试

This should do the trick: 这应该可以解决问题:

<?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>

Some explanation. 一些解释。 The first template matching node()|@* just copies things by default. 默认情况下,第一个匹配node()|@*模板只是复制内容。

The second template matching stuff:v will take over when a stuff:v element is encountered. 遇到stuff:v元素时,匹配stuff:v的第二个模板将接管。 It will iterate over all stuff:p elements in it, and for each of them applies matching templates to its stuff:v ancestor. 它将遍历其中的所有stuff:p元素,并为每个元素将匹配的模板应用于其stuff:v祖先。 However, it enters a mode I named "copying" and calls the templates with a parameter pId which is the id of the p element. 但是,它进入我称为“复制”的模式,并使用参数pId调用模板,参数pId是p元素的ID。 Each element in XML has some implicit id that uniquely identifies it. XML中的每个元素都有一些唯一标识它的隐式ID。

This way we end up in the next template, which also matches stuff:v but only in mode "copying". 这样,我们最终到达了下一个模板,该模板也匹配stuff:v但仅在“复制”模式下。 It accepts a pId parameter, copies the v element and then applies templates to all its attributes and child nodes, no longer with the "copying" mode but with the pId parameter . 它接受一个pId参数,复制v元素,然后将模板应用于其所有属性和子节点,不再使用“复制”模式, 而是使用pId参数 That last part is crucial. 最后一部分至关重要。

The final template matches stuff:p but will only copy it if the id of that element is the same as the one given in the pId parameter. 最终的模板与stuff:p相匹配,但是仅当该元素的id与pId参数中指定的ID相同时才将其复制。

So basically, we get to stuff:v, go through each stuff:p in it, for each of them it goes to stuff:v again in a different mode to match another template (otherwise it would recurse infinitely), and from there copy everything but for stuff:p elements require that they match a parameter passed into the template. 因此,基本上,我们进入stuff:v,遍历其中的每个stuff:p,对于它们中的每一个,它再次以不同的模式进入stuff:v,以匹配另一个模板(否则它将无限递归),然后从那里复制除东西以外的所有内容:p元素都要求它们与传递到模板中的参数匹配。

Why don't you do simply: 为什么不简单地做:

XSLT 1.0 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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM