Copy XML replacing selected node contents in XSLT (2.0)
Here should go questions about transforming XML with XSLT and FOP.
Copy XML replacing selected node contents in XSLT (2.0)
I'm wondering if there is a way in XSLT (2.0 is fine) to copy some part of XML replacing some node values at the same time. Here is an example to visualize the matter:
<invoice>
[...]
<apples>
<apple id=1"><price>100</price></apple>
<apple id=2"><price>120</price></apple>
<apple id=3"><price>90</price></apple>
</apples>
<update-prices>
<modification><price apple-id="1">112</price></modification>
<modification><price apple-id="2">132</price></modification>
<modification><price apple-id="3">102</price></modification>
</update-prices>
[...]
</invoice>
So, I would like to prepare an XSLT stylesheet which copies the whole <invoice> element with its children, but replacing the apple prices [isn't $100 for an apple high enough? damn inflation...] with new prices that are included in the <update-prices> element.
It would be nice to delete the <update-prices> element in the resulting document as well.
So the result XML should look like this:
<invoice>
[...]
<apples>
<apple id=1"><price>112</price></apple>
<apple id=2"><price>132</price></apple>
<apple id=3"><price>102</price></apple>
</apples>
[...]
</invoice>
I would not like to map every possible node that can appear in the XML file accordning to the schema. I would just like to copy and paste the XML replacing some of the values using a pattern. Is there a non-hacker way to do this in XSLT?
<invoice>
[...]
<apples>
<apple id=1"><price>100</price></apple>
<apple id=2"><price>120</price></apple>
<apple id=3"><price>90</price></apple>
</apples>
<update-prices>
<modification><price apple-id="1">112</price></modification>
<modification><price apple-id="2">132</price></modification>
<modification><price apple-id="3">102</price></modification>
</update-prices>
[...]
</invoice>
So, I would like to prepare an XSLT stylesheet which copies the whole <invoice> element with its children, but replacing the apple prices [isn't $100 for an apple high enough? damn inflation...] with new prices that are included in the <update-prices> element.
It would be nice to delete the <update-prices> element in the resulting document as well.
So the result XML should look like this:
<invoice>
[...]
<apples>
<apple id=1"><price>112</price></apple>
<apple id=2"><price>132</price></apple>
<apple id=3"><price>102</price></apple>
</apples>
[...]
</invoice>
I would not like to map every possible node that can appear in the XML file accordning to the schema. I would just like to copy and paste the XML replacing some of the values using a pattern. Is there a non-hacker way to do this in XSLT?
Start off with a copy template
---
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
---
Then have an apple template.
Notice the check for a price modification. Unfortunately this method is a little bit slower, since we have to check every apple for a modification, but I don't entirely see a workaround.
---
<xsl:template match="apple">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:choose>
<xsl:when test="//update-prices/modification/price/@apple-id[.=current()/@id]">
<xsl:apply-templates select="//update-prices/modification/price[@apple-id=current()/@id]"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
---
Don't process the update-prices node directly
---
<xsl:template match="update-prices"/>
---
And add a modification to the price node template so we don't copy the apple-id attribute
---
<xsl:template match="price">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
---
As a side, you can also add a key to the price-modifications if you have a lot of them, and it is worth indexing.
---
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
---
Then have an apple template.
Notice the check for a price modification. Unfortunately this method is a little bit slower, since we have to check every apple for a modification, but I don't entirely see a workaround.
---
<xsl:template match="apple">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:choose>
<xsl:when test="//update-prices/modification/price/@apple-id[.=current()/@id]">
<xsl:apply-templates select="//update-prices/modification/price[@apple-id=current()/@id]"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
---
Don't process the update-prices node directly
---
<xsl:template match="update-prices"/>
---
And add a modification to the price node template so we don't copy the apple-id attribute
---
<xsl:template match="price">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
---
As a side, you can also add a key to the price-modifications if you have a lot of them, and it is worth indexing.
Jump to
- Oxygen XML Editor/Author/Developer
- ↳ Feature Request
- ↳ Common Problems
- ↳ DITA (Editing and Publishing DITA Content)
- ↳ SDK-API, Frameworks - Document Types
- ↳ DocBook
- ↳ TEI
- ↳ XHTML
- ↳ Other Issues
- Oxygen XML Web Author
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Content Fusion
- ↳ Feature Request
- ↳ Common Problems
- Oxygen JSON Editor
- ↳ Feature Request
- ↳ Common Problems
- Oxygen PDF Chemistry
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Feedback
- ↳ Feature Request
- ↳ Common Problems
- Oxygen XML WebHelp
- ↳ Feature Request
- ↳ Common Problems
- XML
- ↳ General XML Questions
- ↳ XSLT and FOP
- ↳ XML Schemas
- ↳ XQuery
- NVDL
- ↳ General NVDL Issues
- ↳ oNVDL Related Issues
- XML Services Market
- ↳ Offer a Service