groovy: изменить существующий xml, суммировать повторяющиеся теги

#xml #groovy

#xml #groovy

Вопрос:

Я новичок в groovy и изо всех сил пытаюсь изменить (или скопировать) и существующий XML-файл, сжимая части, принадлежащие одному и тому же идентификатору. Это пример исходного XML:

 <ROOT>
 <JDE>
   <ID>1</ID>
   <ORDERS>
     <ORDER>123</ORDER>
   </ORDERS>
 </JDE>
 <JDE>
   <ID>1</ID>
   <ORDERS>   
     <ORDER>234</ORDER>
   </ORDERS>
 </JDE>
 <JDE>
   <ID>2</ID>
   <ORDERS>   
     <ORDER>345</ORDER>
   </ORDERS>
 </JDE>
</ROOT>

As you can see, we can have several <JDE> Tags for the same person (ID). Now I need to detect those redundancies and copy all Orders to the first node of this person. The end result shall be this:

<ROOT>
 <JDE>
   <ID>1</ID>
   <ORDERS>
     <ORDER>123</ORDER>
     <ORDER>234</ORDER>
   </ORDERS>
 </JDE>
 <JDE>
   <ID>2</ID>
   <ORDERS>   
     <ORDER>345</ORDER>
   </ORDERS>
 </JDE>
</ROOT> 


Я не понимаю, могу ли я добиться этого, изменив файл с помощью XMLParser или мне нужно создать другой файл с помощью MarkupBuilder?

Это мое кодирование до сих пор (в основном для выявления дубликатов):

 def body = message.getBody(String.class)  //xml file          
def xmlParser = new XmlParser()
def List = xmlParser.parseText(body)
def IdList = []

Root.JDE.each{               
        def ID = it.ID

        if ( IdList.contains(ID) )
        {  
           //ID already found, now iterate again to find first occurence
           //copy the order node and delete the JDE node of the duplicate
                // --> ifI need to iterate again, can I use Root.JDE.each again?
        }
        else
        {
            //do nothing or copy node to a target xml file
            IdList.add(Employee_ID)
        }
}
 

Ответ №1:

Почти идентичный ответ, но с использованием замыкания для поиска заказов по заданному идентификатору:

 import groovy.xml.MarkupBuilder

def body = '''
<ROOT>
 <JDE>
   <ID>1</ID>
   <ORDERS>
     <ORDER>123</ORDER>
   </ORDERS>
 </JDE>
 <JDE>
   <ID>1</ID>
   <ORDERS>
     <ORDER>234</ORDER>
   </ORDERS>
 </JDE>
 <JDE>
   <ID>2</ID>
   <ORDERS>
     <ORDER>345</ORDER>
   </ORDERS>
 </JDE>
</ROOT>
'''

def root = new XmlParser().parseText(body)
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)

ids = root.JDE.ID.collect { it.text() }.unique()
def orderById = { id ->
    root.JDE.ID
        .findAll { it.text() == id }
        .collect { it.parent().ORDERS.ORDER.text() }
}

xml.ROOT() {
    ids.each { id ->
        JDE() {
            ID(id)
            ORDERS() {
                orderById(id).each { o ->
                    ORDER(o)
                }
            }
        }
    }
}

println writer.toString()

 

Ответ №2:

Рабочий пример здесь

Вероятно, будет проще писать, тестировать и поддерживать, если мы разделим это на два этапа: создадим карту из старой структуры и используем карту для создания новой модели.

Рассмотрим:

 def xmlParser = new XmlParser()
def root = xmlParser.parseText(body)

// 1. build map
def map = [:].withDefault{ key -> [] }

root.JDE.each { jde ->
    def id = jde.ID.text()
    jde.ORDERS.each { order ->
        map[id] << order.text()
    }
}

// 2. use map to build new XML structure
def writer = new StringWriter()
new groovy.xml.MarkupBuilder(writer).ROOT {
    map.each { id, orderIds ->
        JDE() {
            ID(id)
            ORDERS() {
                orderIds.each { orderId ->
                    ORDER(orderId)
                }
            }
        }
    }
}

println writer.toString()
 

Комментарии:

1. Нет проблем… Пожалуйста, поддержите любые полезные ответы и «примите» (отметьте галочкой) тот, который отвечает на ваш вопрос.