0

I have got 2 XML files.

1.xml

<abc>
....
....
</abc>

<xyz attrib1='1234'>
...
...
</xyz>

2.xml

<abc>
xxx
xxx
</abc>
<xyz attrib2='4321'>
xxx
xxxx
</xyz>

I need to use shell scripting to replace the content of 'xyz' tag in file 1.xml by the content in 2.xml to give me final file like:

<abc>
    ....
    ....
    </abc>
    <xyz attrib2='4321'>
    xxx
    xxxx
    </xyz>
1

With sed:

sed -n '/<xyz[ >]/,/<\/xyz>/p' 2.xml | \
sed '/<xyz[ >]/,/<\/xyz>/ { /<\/xyz>/! d; r /dev/stdin
    D; }' 1.xml >output.xml

Please note that there must be a newline after /dev/stdin.

Another way with sed, cleaner but less efficient:

{
    sed '/<xyz[ >]/,$d' 1.xml
    sed -n '/<xyz[ >]/,/<\/xyz>/p' 2.xml
    sed '1,/<\/xyz>/d' 1.xml
} >output.xml
4
  • Trying it in a single sed also works, but made it ugly for me: sed -n "H;1h;\${g;s/\n/<<>>/g;s/<xyz .*xyz>\(.*\)<abc.*\(<xyz .*xyz>\).*/\2\1/;s/<<>>/\n/g;p}" 1.xml 2.xml.
    – Philippos
    Apr 5 '17 at 6:47
  • @Philippos That potentially reads a lot of stuff in memory, but I suppose it's still a valid answer. Apr 5 '17 at 6:50
  • did not work. It does not replace the complete <xyz> tag with the content of 2.xml. It just grabs the content of 2.xml between the tags and prints it Apr 5 '17 at 7:12
  • @AbhishekKothari Sorry to hear that. It works fine here. shrug Apr 5 '17 at 7:18
1

A correct (though verbose) way to do this would be to use an XML-aware utility, instead of a generic text processing tools.

E.g. using XSTL transformation with xsltproc:

xsltproc - 1.xml <<EOF
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- Identity template (copy input to output) -->
    <xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>   
    </xsl:copy>
    </xsl:template>

    <!-- Replace //xyz with its counterpart from 2.xml -->
    <xsl:template match="//xyz">
        <xsl:copy-of select="document('2.xml')//xyz"/>
    </xsl:template>
</xsl:stylesheet>
EOF

This will correctly replace //xyz in 1.xml with the //xyz from 2.xml, regardless of text encoding, formatting, usage of entity references e.t.c.

0
sed "
    /<xyz/,/<\/xyz>/c\
        $(
            sed -n '
                /<xyz/{
                    :a;
                    N;
                    /<\/xyz>/! ba;
                    s/\n/\\&/gp;
                    }
                ' 2.xml
        )
    " 1.xml

As for me it's much easy to put necessary lines from 2.xml and substitute (c) apropriate line(s) in 1.xml Note: c command couldn't accept multiline input so we have to add \ between lines.

0
perl -0777ne '                                # slurp xmls
   $tag2 or ($tag2) = /(<xyz.*<\/xyz>)/s;     # grab tag <xyz> from 2.xml
   @ARGV or print s|<xyz.+?</xyz>|$tag2|srg;  # replace tag <xyz> in 1.xml globally
' 2.xml 1.xml

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.