3

I have an XML file with multiple child elements which have the same tag-name, ex. <Name>Luigi</Name>, <Name>Mario</Name>, <Name>Peach</Name>. Here is a mock-up of what my input file looks like:

<!-- names.xml -->
<Names>
    <Name>Luigi</Name>
    <Name>Mario</Name>
    <Name>Peach</Name>
</Names>

When I throw this file into Excel for analysis it creates a new record for each Name element. This is awesome from a readability perspective, but it makes it difficult to discern if I have lots of duplicate data outside of the name fields.

What I want to do is rename the tags to Name1, Name2, Name3 so that they all appear on the same row when I import them into Excel. That way I'll be able to find records that are useless to me or that contain duplicates - without having to constantly look at the raw data.

In other words, I want a script or command which produces the following output:

<!-- names.xml -->
<Names>
    <Name1>Luigi</Name1>
    <Name2>Mario</Name2>
    <Name3>Peach</Name3>
</Names>

Is it possible to do this with a sed command or other Unix script?

5
  • 1
    It's not clear to me what you want your output to be. Can you give a small example input file and example output file?
    – igal
    Nov 10, 2017 at 14:56
  • I'd like my output to be: <Name>Luigi</Name>, <Name1>Mario</Name1>, <Name2>Peach</Name2>
    – Jakloom
    Nov 10, 2017 at 15:14
  • 1
    Please provide a segment of your XML file, including parent elements. (Make up the data values if you like.) That will give tools like xmlstarlet something to grip on to. Remember to put it in your question, not here in the comments.
    – roaima
    Nov 10, 2017 at 15:20
  • I made a guess as to what you're looking for and posted a solution. Let me know if it looks like it's doing the right thing and I'll add some explanation.
    – igal
    Nov 10, 2017 at 15:33
  • In general what you're asking for is bad practice. XML that uses composite element names like this will be much more difficult to process. Dec 23, 2021 at 11:20

1 Answer 1

3

Since you specifically asked for sed, here is a sed/bash script that should do what you want, provided that each <Name> element is opened and closed on the same line:

(IFS='';
n=0;
while read line; do
    if echo "${line}" | grep -Pq "<Name>\w+</Name>"; then
        ((n++));
        echo "${line}" | sed "s/<Name>\(\w\+\)<\/Name>/<Name${n}>\1<\/Name${n}>/";
    else
        echo "${line}";
    fi;
done) < names.xml

I tested it with this input file:

<!-- names.xml -->
<Names>
    <Name>Luigi</Name>
    <Name>Mario</Name>
    <Name>Peach</Name>
</Names>

And it produced the following output:

<Names>
    <Name1>Luigi</Name1>
    <Name2>Mario</Name2>
    <Name3>Peach</Name3>
</Names>

That said, this seems like a good candidate for a language with an XML parsing library. Here is a Python script that does what you want:

#!/usr/bin/env python2
# -*- encoding: ascii -*-

# add_suffix.py

import sys
import xml.etree.ElementTree

# Load the data
tree = xml.etree.ElementTree.parse(sys.argv[1])
root = tree.getroot()

# Update the XML tree
suffix = 0
for name in root.iter("Name"):
    suffix += 1
    name.tag += str(suffix)

# Write out the updated data
tree.write(sys.argv[2])

Run it like this:

python add_suffix.py names.xml new_names.xml
1
  • That output is exactly what I'm looking for!
    – Jakloom
    Nov 10, 2017 at 15:41

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.