I have a xml file 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>
<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
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.
The second template matching stuff:v
will take over when a stuff:v element is encountered. It will iterate over all stuff:p elements in it, and for each of them applies matching templates to its stuff:v ancestor. However, it enters a mode I named "copying" and calls the templates with a parameter pId
which is the id of the p element. Each element in XML has some implicit id that uniquely identifies it.
This way we end up in the next template, which also matches stuff:v
but only in mode "copying". 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 . 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.
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.
Why don't you do simply:
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>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.