Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy edit XML file, keep comments, line breaks

Tags:

xml

groovy

I would like to edit an existing XML file while preserving it's original layout. This includes new lines, comments etc. Editing is composed of finding elements inside the XML and modifying the text value.

My first try was using XMLParser with XmlUtil.serialize but that does not meet the requirement.

Anyone is aware of any alternative to XMLParser where edits are "in place" of the original XML string? If not, perhaps there is a library that performs search using XPath/GPath and just return the location of the find so I can do StringBuilder.replace.

EDIT:

For now I made this function, to find string indexes of XML node (that I can find using xpath) then I am doing replace on the indexes. Works fine for simple nodes <node>value</node>:

def find_location_by_node(xmlString, root_xml, node)
{
    current_index = 0;

    for(current_node in root_xml.depthFirst())
    {
      node_name = current_node.name().getLocalPart()
      current_index = xmlString.indexOf('<' + node_name, current_index);

      if(current_node == node)
      {
        end_tag = '</' + node_name + '>';
        end_tag_index = xmlString.indexOf(end_tag, current_index) + end_tag.length();

        return [current_index, end_tag_index];
      }
    }

  return -1;
}
like image 588
mbdev Avatar asked Jan 20 '11 07:01

mbdev


1 Answers

You could update your XML with DOMCategory. DOM will keep your original layout.

import groovy.xml.DOMBuilder

def input = '''
<shopping>
    <category type="groceries">
        <item>Chocolate</item>
        <item>Coffee</item>
    </category>
    <category type="supplies">
        <item>Paper</item>
        <item quantity="4">Pens</item>
    </category>
    <category type="present">
        <item when="Aug 10">Kathryn's Birthday</item>
        <item>Chocolate</item>
    </category>
</shopping>

'''

def doc = DOMBuilder.parse(new StringReader(input))
def root = doc.documentElement
use(groovy.xml.dom.DOMCategory) {
    def chocolate = root.depthFirst().grep{it.text() == "Chocolate"}
    chocolate*.value = "Nutella"
}

def result = groovy.xml.dom.DOMUtil.serialize(root)
println result
like image 75
rochb Avatar answered Nov 01 '22 14:11

rochb