Reputation: 1531
I have xml that approximates:
<?xml version="1.0" encoding="UTF-8"?>
<book>
<num>Book 1.</num>
<head> Title</head>
<chapter>
<num>1.</num>
<head> The Begining</head>
<p>content</p>
</chapter>
<num>12. </num><p>we want that number untouched</p>
<chapter>
<num>2.</num>
<head> The Middle</head>
<p>content</p>
</chapter>
<head>Heads Occur</head><p>we want that head untouched</p>
</book>
Where a <num>
is followed immediately by a <head>
I want to merge the two together. I use this xsl, with some success, but not in all use-cases.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="num[following-sibling::head]">
<mergedhead>
<xsl:apply-templates select="node()|@*"/>
<xsl:value-of select="following-sibling::head"/>
</mergedhead>
</xsl:template>
<!-- keep the old head from showing up in the new output-->
<xsl:template match="head[preceding-sibling::num]"/>
</xsl:stylesheet>
following::sibling
and preceding::sibling
work, but not in all use-cases. Sometimes they pull in <num>
and <head>
that are not directly next to each other. Output of my flawed XSL:
<?xml version="1.0" encoding="UTF-8"?>
<book>
<mergedhead>Book 1. Title</mergedhead>
<chapter>
<mergedhead>1. The Begining</mergedhead>
<p>content</p>
</chapter>
<mergedhead>12. Heads Occur</mergedhead><p>we want that number untouched</p>
<chapter>
<mergedhead>2. The Middle</mergedhead>
<p>content</p>
</chapter>
<p>we want that head untouched</p>
</book>
You can see that it merged the #12, which I want untouched, with the 'heads occur' which I also want untouched. I know it's because they are siblings, even there are other nodes in between. I think the answer I want is in position()
. But I have not been successful with that.
For reference, the desired out is below:
<?xml version="1.0" encoding="UTF-8"?>
<book>
<mergedhead>Book 1. Title</mergedhead>
<chapter>
<mergedhead>1. The Begining</mergedhead>
<p>content</p>
</chapter>
<num>12. </num><p>we want that number untouched</p>
<chapter>
<mergedhead>2. The Middle</mergedhead>
<p>content</p>
</chapter>
<head>Heads Occur</head><p>we want that head untouched</p>
</book>
Upvotes: 0
Views: 101
Reputation: 3428
Try following xslt if it fulfils your requirement.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- Take all following sibling elements (i.e. following-sibling:*) regardless their names, from them take first one (i.e. [1]) and test it if it is head (i.e. [self::head]-->
<xsl:template match="num[following-sibling::*[1][self::head]]">
<mergedhead>
<xsl:apply-templates select="node()|@*"/>
<!-- Take the first following sibling -->
<xsl:value-of select="following-sibling::head[1]"/>
</mergedhead>
</xsl:template>
<!-- similar to num template -->
<xsl:template match="head[preceding-sibling::*[1][self::num]]"/>
</xsl:stylesheet>
Upvotes: 2