2

I was looking at a possible XML-based solution to another question. I'm aware of its accepted answer, which offers sed and python solutions.

The given XML fragment is:

<Names>
    <Name>Luigi</Name>
    <Name>Mario</Name>
    <Name>Peach</Name>
</Names>

and the requirement is to change the <Name/> element names to a sequence <Name1/>, <Name2/>, <Name3/>, etc.

Using xmlstarlet I can rename the <Name/> element values to an fixed value with something like this

xmlstarlet ed -u '//Name' -v 'Another' names.xml

<Names>
  <Another>Luigi</Another>
  <Another>Mario</Another>
  <Another>Peach</Another>
</Names>

And I can even change the element values to an expression with -x (--expr).

But for editing element names themselves there is no -x (--expr) option as an alternative to the -v (--value) option, so I cannot use something like this:

xmlstarlet ed -u '//Name' -x 'concat(., position())' names.xml

Using an XML-aware tool such as xmlstarlet, is it possible to transform the input XML to differentiate the <Name/> elements like this, and if so, how?

<Names>
    <Name1>Luigi</Name1>
    <Name2>Mario</Name2>
    <Name3>Peach</Name3>
</Names>
  • This should be doable via XSLT, but not trivial. – Ignacio Vazquez-Abrams Nov 10 '17 at 23:47
  • @IgnacioVazquez-Abrams I thought it might be possible with XSLT but I don't know enough about it to know where to begin. It just seems strange that to edit XML I should have to revert to a non-XML-aware tool such as sed! – roaima Nov 10 '17 at 23:48
  • You shouldn't have to. XSLT does have the ability to emit arbitrary tags, but you'll probably have to recurse templates in order to get the numbering. – Ignacio Vazquez-Abrams Nov 10 '17 at 23:49
  • This isn't anything specific to Unix or Linux. – Ignacio Vazquez-Abrams Nov 11 '17 at 0:03
2

My experience with XML command-line tools has left me with the feeling that there's a lot to be desired. Almost without fail I find myself giving up and just using Python. That said, I think I have an XQuery solution to this problem that works with the basex utility. Here is the XQuery expression:

<!-- xml_rename_sequence.xquery -->
for $name at $position in doc('names.xml')//Name
return rename node $name as concat(name($name),$position)

And here is the XML data file:

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

Here is how we run the script (it modifies the file in-place):

basex -u xml_rename_sequence.xquery

And here is the updated data file:

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

I also tried using the following tools (without success):

Here were some posts I found regarding incrementing a counter in XQuery:

And here were some other references I used:

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.