0

Find a specific xml tag and replace the text inside tags to some parameterized value. Multiple occurrences need to be replaced.

Sample file content:

<a>abc</a>

Current attempt:

sed -i "s/\(<a>\).*\(<\/a>\)/\(<a>\)$param\(<\/a>\)/g" script.xml

Desired outcome: if param=111 then

<a>111</a>
1
  • 1
    Welcome to the site. Your post is rather hard to understand as it is. Please use proper formatting to highlight (1) sample input (2) what you already tried (3) where you ran into problems - it is currently not clear what your question/problem actually is. – AdminBee Jun 19 '20 at 12:49
1
  1. Those \(\) are superfluous in your case. Just write sed -i "s/<a>.*<\/a>/<a>$param<\/a>/g" script.xml
  2. If your string contains /, it's easier to read if you use a different separator char: sed -i "s_<a>.*</a>_<a>$param</a>_g" script.xml
  3. The g option suggests that there could be more than one <a> tag on one line. This is a problem: The .* will match the next </a>, more stuff and the last <a>, so prevent to include other tags: sed -i "s_<a>[^<]*</a>_<a>$param</a>_g" script.xml
  4. Please note that this will not work if other tags are nested inside the <a> tag or if $param contains special characters like " or \
1

I would do this in Perl instead of sed since Perl supports non-greedy matches:

perl -i -pe "s|<a>.+?</a>|<a>$param</a>|g" file

The .+? means "match the shortest possible string", so this will find the shortest string between an <a> and an </a>.

I must stress, however, that this is very likely to fail on even slightly complex XML documents and you really should consider using a dedicated XML parser instead.

1

I know you asked for a sed solution, but I generally recommend an XML-based tool (of which there are a number) instead of sed when dealing with an XML document other than a very simple one.

Suppose this is my XML document (doc.xml):

<?xml version="1.0"?>
<xml>
    <c><a>abc</a></c>
    <b>
        <a>abc</a>
        <a>abc</a>
    </b>
    <a parm="FPM">abc</a>
</xml>

I am going to use the following XML stylesheet, style.xsl, to transform the document into the desired format.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name = "value" />

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="a/text()[.='abc']">
        <xsl:value-of select = "$value" />
    </xsl:template>

</xsl:stylesheet>

I use the xsltproc tool, which is installed by default on most major Linux distributions, to perform the transformation:

$ xsltproc --stringparam value "111" style.xsl doc.xml
<?xml version="1.0"?>
<xml>
    <c><a>111</a></c>
    <b>
        <a>111</a>
        <a>111</a>
    </b>
    <a parm="FPM">111</a>
</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.