How do I search and replace a large block of text?

99 Views Asked by At

I only have awk, sed, xmllint and ex available to me.

I need to modify a text file. What it is now:

        <!--
        <Connector port="8090" connectionTimeout="20000" redirectPort="8443"
                   maxThreads="48" maxPostSize="16777216" minSpareThreads="10"
                   enableLookups="false" acceptCount="10" URIEncoding="UTF-8"
                   protocol="org.apache.coyote.http11.Http11NioProtocol"
                   scheme="http" proxyName="<subdomain>.<domain>.com" proxyPort="80"/>
        -->

I need to remove the XML comments and change the proxyName variable. What I need to change it to:

        <Connector port="8090" connectionTimeout="20000" redirectPort="8443"
                   maxThreads="48" maxPostSize="16777216" minSpareThreads="10"
                   enableLookups="false" acceptCount="10" URIEncoding="UTF-8"
                   protocol="org.apache.coyote.http11.Http11NioProtocol"
                   scheme="http" proxyName="proxy.company.com" proxyPort="80"/>

There are several instances of this block in this file. I only want to change the block that contains:

scheme="http" proxyName="<subdomain>.<domain>.com" proxyPort="80"/>

Thanks!

2

There are 2 best solutions below

2
Daniel Haley On

If you can use xmllint you can probably use xmlstarlet. If so, you can use XSLT to do this. Unfortunately xmlstarlet only supports XSLT 1.0 so it's not a pretty solution, but it works.

XML Input (input.xml)

<doc>
    <!--
    <Connector port="8090" connectionTimeout="20000" redirectPort="8443"
               maxThreads="48" maxPostSize="16777216" minSpareThreads="10"
               enableLookups="false" acceptCount="10" URIEncoding="UTF-8"
               protocol="org.apache.coyote.http11.Http11NioProtocol"
               scheme="http" proxyName="<subdomain>.<domain>.com" proxyPort="80"/>
    -->
    <foo/>
    <!--
    <Connector port="8090" connectionTimeout="20000" redirectPort="8443"
               maxThreads="48" maxPostSize="16777216" minSpareThreads="10"
               enableLookups="false" acceptCount="10" URIEncoding="UTF-8"
               protocol="org.apache.coyote.http11.Http11NioProtocol"
               scheme="http" proxyName="ignore.me" proxyPort="80"/>
    -->
</doc>

XSLT 1.0 (test.xsl)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="comment()[
        contains(.,'scheme=&quot;http&quot;') and 
        contains(.,'proxyName=&quot;&lt;subdomain>.&lt;domain>.com&quot;') and 
        contains(.,'proxyPort=&quot;80&quot;')]">
        <xsl:value-of select="substring-before(.,'proxyName=&quot;&lt;subdomain>.&lt;domain>.com&quot;')" disable-output-escaping="yes"/>
        <xsl:text>proxyName="proxy.company.com"</xsl:text>
        <xsl:value-of select="substring-after(.,'proxyName=&quot;&lt;subdomain>.&lt;domain>.com&quot;')" disable-output-escaping="yes"/>
    </xsl:template>
    
</xsl:stylesheet>

Command line/Output (This can be redirected to an output file.)

==> xmlstarlet tr test.xsl input.xml 
<?xml version="1.0"?>
<doc>
    <Connector port="8090" connectionTimeout="20000" redirectPort="8443"
               maxThreads="48" maxPostSize="16777216" minSpareThreads="10"
               enableLookups="false" acceptCount="10" URIEncoding="UTF-8"
               protocol="org.apache.coyote.http11.Http11NioProtocol"
               scheme="http" proxyName="proxy.company.com" proxyPort="80"/>
    <foo/><!--
    <Connector port="8090" connectionTimeout="20000" redirectPort="8443"
               maxThreads="48" maxPostSize="16777216" minSpareThreads="10"
               enableLookups="false" acceptCount="10" URIEncoding="UTF-8"
               protocol="org.apache.coyote.http11.Http11NioProtocol"
               scheme="http" proxyName="ignore.me" proxyPort="80"/>
    --></doc>
0
LMC On

Assuming a XML sample as

<context>
            <!--
        <Connector port="8090" connectionTimeout="20000" redirectPort="8443"
                   maxThreads="48" maxPostSize="16777216" minSpareThreads="10"
                   enableLookups="false" acceptCount="10" URIEncoding="UTF-8"
                   protocol="org.apache.coyote.http11.Http11NioProtocol"
                   scheme="http" proxyName="subdomain.example.com" proxyPort="80"/>
        -->
    <other>test</other>
</context>

Bash script

#!/bin/bash

# Extract comment content to a variable
comm="$(xmllint --xpath 'normalize-space(/context/descendant::comment()[contains(.,"example.com")])' tmp.xml | sed -ze 's/\n/\&#xA;/g')"
# get everything else
content="$(xmllint --xpath '/context/*[not(descendant::comment()[contains(.,"example.com")])]' tmp.xml | sed -ze 's/\n/\&#xA;/g')"
# set contents again

printf "%s\n" 'cd /context' "set ${comm} ${content}" 'save' 'bye' | xmllint --shell tmp.xml

Comment turned into element

<?xml version="1.0" encoding="UTF-8"?>
<context><Connector port="8090" connectionTimeout="20000" redirectPort="8443" maxThreads="48" maxPostSize="16777216" minSpareThreads="10" enableLookups="false" acceptCount="10" URIEncoding="UTF-8" protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="http" proxyName="subdomain.example.com" proxyPort="80"/>
 <other>test</other>
</context>

Next, change the attribute value as described here Modifying in line attribute in XML using xmllint