1

I'm trying to write a shell script which will take, as input, a set of name/value pairs and an XML file.

The aim is to search within the XML file for the "name" string from the name/value pairs file (demarcated with tags), and replace the "value" string defined at the same level of the XML file (demarcated with tags).

e.g.

Name/value pairs file

trousers=blue
hat=red
shoes=brown

Input XML file

<application>
    <Pairs>
        <Pair>
            <name>trousers</name>
            <value>black</value>
        </Pair>
        <IrritatingExtraLayer>
            <Pair>
                <name>hat</name>
                <value>green</value>
            </Pair>
        </IrritatingExtraLayer>
        <Pair>
            <name>shirt</name>
            <value>orange</value>
        </Pair>
    </Pairs>
</application>

Expected output file

<application>
    <Pairs>
        <Pair>
            <name>trousers</name>
            <value>blue</value>
        </Pair>
        <IrritatingExtraLayer>
            <Pair>
                <name>hat</name>
                <value>red</value>
            </Pair>
        </IrritatingExtraLayer>
        <Pair>
            <name>shirt</name>
            <value>orange</value>
        </Pair>
    </Pairs>
</application>

I have already created a script which can do this using xmlstarlet, however it is very slow (the files I am working with are thousands of lines long). The main code snippet (ignoring pre-processing and post-processing) from my script is:

for line in ${namevaluepairs}; do
                name=$(echo ${line} | cut -d'=' -f1)
                value=$(echo ${line} | cut -d'=' -f2)

                outputxml=$(echo ${outputxml} | xmlstarlet ed -u "//Pair/[name='${name}']/value" -v "${value}" )
done

What can I do to improve this?

1 Answer 1

1

I usually use xsh for similar tasks. I would be interested how fast the following compared to the xmlstarlet.

perl { 
    open $FH, '<', 'namevalues' or die $!;
    while (<$FH>) {
        chomp;
        ($n, $v) = split /=/;
        $h->{$n} = $v;
    }
} ;
open 1.xml ;
for //name {
    $v = xsh:lookup('h', text()) ;
    if $v set ../value $v ;
}
save :b ;

The trick is to store the name-value pairs in a hash (map, dictionary), then process all the names and retrieve the corresponding values from the hash.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.