Home > database >  Copy a huge xml using copy-of but replacing just one value in it
Copy a huge xml using copy-of but replacing just one value in it

Time:07-12

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>
  • Related