I want to copy a big xml as-it-is but need to change just one value in it.
For example let's say I have the below xml:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<row>
<col1>A</col1>
<col2>B</col2>
<col3>C</col3>
<col4>D</col4>
<col5>E</col5>
<col6>F</col6>
<col7>G</col7>
<col8>H</col8>
<col9>I</col9>
<col10>J</col10>
</row>
<row>
<col1>A</col1>
<col2>B</col2>
<col3>C</col3>
<col4>D</col4>
<col5>E</col5>
<col6>F</col6>
<col7>G</col7>
<col9>I</col9>
<col10>J</col10>
</row>
</root>
Now, I want the entire xml as it is but modify one value - col8
Expected output file:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<row>
<col1>A</col1>
<col2>B</col2>
<col3>C</col3>
<col4>D</col4>
<col5>E</col5>
<col6>F</col6>
<col7>G</col7>
<col8>NEW</col8> <------ Updated data
<col9>I</col9>
<col10>J</col10>
</row>
<row>
<col1>A</col1>
<col2>B</col2>
<col3>C</col3>
<col4>D</col4>
<col5>E</col5>
<col6>F</col6>
<col7>G</col7>
<col8>ADD</col8> <------ Added data
<col9>I</col9>
<col10>J</col10>
<row>
</root>
My xml has around 5000 lines of data in which I have to update just one value. copy-of seems to copy everything and not allowing me to update one value. Please help if this is possible.
CodePudding user response:
Try the standard approach:
XSLT 3.0
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="col8">
<xsl:copy>NEW</xsl:copy>
</xsl:template>
</xsl:stylesheet>
CodePudding user response:
To inject missing col8
entries, add one more template:
<xsl:template match="col7[not(../col8)]">
<xsl:copy-of select="."/>
<col8>ADD</col8>
</xsl:template>
This assumes that col7
always exists.
CodePudding user response:
If you need if you need to work with "col8" differently if it exists or it does not, you could do it like this :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes" html-version="5"/>
<!-- Case where col8 exists -->
<xsl:template match="col8">
<xsl:copy>NEW</xsl:copy>
</xsl:template>
<!-- Case where col8 needs to be added -->
<xsl:template match="row[not(col8)]">
<xsl:copy>
<xsl:apply-templates/>
<col8>ADD</col8>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Else this would take care of both cases :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes" html-version="5"/>
<xsl:template match="row">
<xsl:copy>
<xsl:apply-templates select="*[not(self::col8)]"/>
<col8>NEW DATA</col8>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
And if you need the columns to be in numerical order :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes" html-version="5"/>
<xsl:template match="row">
<xsl:variable name="temp">
<xsl:apply-templates select="*[not(self::col8)]"/>
<col8>NEW DATA</col8>
</xsl:variable>
<xsl:copy>
<xsl:for-each select="$temp/*">
<xsl:sort select="replace(name(.),'col','')" data-type="number"/>
<xsl:sequence select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>