Reputation: 3
I want to transform the following XML-data to the desired output shown below - without success until now. So I hope of an input from an expert relating the xsl. Thank you in advance.
Input XML-Data
<?xml version="1.0" encoding="utf-8"?>
<pages>
<page number="1">
<pageArticles>
<articleID id="100"/>
<articleID id="200"/>
<articleID id="300"/>
</pageArticles>
</page>
<page number="5">
<pageArticles/>
</page>
<page number="9">
<pageArticles>
<articleID id="400"/>
<articleID id="500"/>
</pageArticles>
</page>
</pages>
Desired Ouput
<?xml version="1.0" encoding="utf-8"?>
<pages>
<page>
<number>1</number>
<articleID>100</articleID>
</page>
<page>
<number>1</number>
<articleID>200</articleID>
</page>
<page>
<number>1</number>
<articleID>300</articleID>
</page>
<page>
<number>5</number>
<articleID></articleID>
</page>
<page>
<number>9</number>
<articleID>400</articleID>
</page>
<page>
<number>9</number>
<articleID>500</articleID>
</page>
</pages>
Many thanks in advance for any assistance! Urs
Upvotes: 0
Views: 68
Reputation: 167716
Write a template for those articleID
elements to collect the number from the grandparent and add a template for empty pageArticles
:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
expand-text="yes"
version="3.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="pages">
<xsl:copy>
<xsl:apply-templates select="page/pageArticles"/>
</xsl:copy>
</xsl:template>
<xsl:template match="pageArticles[not(has-children())]">
<page>
<number>{../@number}</number>
<articleID/>
</page>
</xsl:template>
<xsl:template match="articleID">
<page>
<number>{../../@number}</number>
<articleID>{@id}</articleID>
</page>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/bFDb2BT and the above is XSLT 3. In earlier version of XSLT you have to replace the text value templates (e.g. {../@number}
) with xsl:value-of
(e.g. <xsl:value-of select="../@number"/>
) and the predicate [not(has-children())]
with [not(node()]
.
Upvotes: 0
Reputation: 29052
This XSLT-1.0 stylesheet does the job:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="text()" />
<xsl:template match="/pages">
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="//articleID | pageArticles[not(*)]">
<page>
<number><xsl:value-of select="ancestor::page/@number[1]" /></number>
<articleID><xsl:value-of select="@id" /></articleID>
</page>
</xsl:template>
</xsl:stylesheet>
Output is:
<pages>
<page>
<number>1</number>
<articleID>100</articleID>
</page>
<page>
<number>1</number>
<articleID>200</articleID>
</page>
<page>
<number>1</number>
<articleID>300</articleID>
</page>
<page>
<number>5</number>
<articleID/>
</page>
<page>
<number>9</number>
<articleID>400</articleID>
</page>
<page>
<number>9</number>
<articleID>500</articleID>
</page>
</pages>
Upvotes: 1