Reputation: 363
My XML is very flat, and here is an example:
<?xml version="1.0" encoding="UTF-8"?>
<Elements>
<Header>
<Divison>A</Divison>
<ParentNumber>2016041330</ParentNumber>
</Header>
<Header>
<Divison>C</Divison>
<ParentNumber>2016041323</ParentNumber>
</Header>
<Element>
<Number>2016041312</Number>
<ParentNumber>2016041330</ParentNumber>
<Risk>8</Risk>
</Element>
<Element>
<Number>2016041342</Number>
<ParentNumber>2016041323</ParentNumber>
<Risk>2</Risk>
</Element>
<Element>
<Number>2016041318</Number>
<ParentNumber>2016041330</ParentNumber>
<Risk>0</Risk>
</Element>
<Element>
<Number>2016041330</Number>
<ParentNumber>2016041323</ParentNumber>
<Risk>7</Risk>
</Element>
</Elements>
And they need to be nested in such a way that it displays as such:
<?xml version="1.0" encoding="UTF-8"?>
<Elements>
<Header>
<Divison>C</Divison>
<ParentNumber>2016041323</ParentNumber>
<Element>
<Number>2016041342</Number>
<ParentNumber>2016041323</ParentNumber>
<Risk>2</Risk>
</Element>
<Header>
<Divison>A</Divison>
<ParentNumber>2016041330</ParentNumber>
<Risk>7</Risk>
<Element>
<Number>2016041312</Number>
<ParentNumber>2016041330</ParentNumber>
<Risk>8</Risk>
</Element>
<Element>
<Number>2016041318</Number>
<ParentNumber>2016041330</ParentNumber>
<Risk>0</Risk>
</Element>
</Header>
</Header>
</Elements>
I tried it with the following transformation:
(Special thanks to michael.hor257k)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="child-by-parent" match="Header | Element" use="ParentNumber" />
<xsl:key name="parent" match="Header | Element" use="Number" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Elements">
<xsl:copy>
<xsl:apply-templates select="*[not(key('parent', ParentNumber))]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Header | Element">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:apply-templates select="key('child-by-parent', Number)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
with the following result:
<?xml version="1.0" encoding="UTF-8"?>
<Elements>
<Header>
<Divison>C</Divison>
<ParentNumber>2016041323</ParentNumber>
</Header>
<Element>
<Number>2016041342</Number>
<ParentNumber>2016041323</ParentNumber>
<Risk>2</Risk>
</Element>
<Element>
<Number>2016041330</Number>
<ParentNumber>2016041323</ParentNumber>
<Risk>7</Risk>
<Header>
<Divison>A</Divison>
<ParentNumber>2016041330</ParentNumber>
</Header>
<Element>
<Number>2016041312</Number>
<ParentNumber>2016041330</ParentNumber>
<Risk>8</Risk>
</Element>
<Element>
<Number>2016041318</Number>
<ParentNumber>2016041330</ParentNumber>
<Risk>0</Risk>
</Element>
</Element>
</Elements>
The [element] tag contains two kinds of information: number and parentnumber. The number is the distinct number of the [element]. The parentnumber references to another [element]. Are both the number and the parentnumber corresponding to a [header], then the [element] serves as a link and can be dissolved. However, if only the parentnumber is corresponding to the [header], than this assigns the [element] tag to a [header] tag.
Upvotes: 0
Views: 1622
Reputation: 117073
I don't understand the logic by which you get your result. AFAICS, you have three elements with no parent node:
<Header>
<Divison>C</Divison>
<ParentNumber>2016041323</ParentNumber>
</Header>
<Element>
<Number>2016041342</Number>
<ParentNumber>2016041323</ParentNumber>
</Element>
<Element>
<Number>2016041330</Number>
<ParentNumber>2016041323</ParentNumber>
</Element>
so I would expect these to be siblings at the top level of the hierarchy. Then you would have each of these three branches nest their descendants recursively - to obtain:
<Elements>
<Header>
<Divison>C</Divison>
<ParentNumber>2016041323</ParentNumber>
</Header>
<Element>
<Number>2016041342</Number>
<ParentNumber>2016041323</ParentNumber>
</Element>
<Element>
<Number>2016041330</Number>
<ParentNumber>2016041323</ParentNumber>
<Header>
<Divison>A</Divison>
<ParentNumber>2016041330</ParentNumber>
</Header>
<Element>
<Number>2016041312</Number>
<ParentNumber>2016041330</ParentNumber>
</Element>
<Element>
<Number>2016041318</Number>
<ParentNumber>2016041330</ParentNumber>
</Element>
</Element>
</Elements>
This could be achieved by:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="child-by-parent" match="Header | Element" use="ParentNumber" />
<xsl:key name="parent" match="Header | Element" use="Number" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Elements">
<xsl:copy>
<xsl:apply-templates select="*[not(key('parent', ParentNumber))]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Header | Element">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:apply-templates select="key('child-by-parent', Number)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1