Изменить имя XML-тега

Я хочу преобразовать XML-документ, который я проанализировал с XmlSlurper. (Идентичные) имена тегов XML должны быть заменены значением id атрибут; все остальные атрибуты должны быть удалены. Начиная с этого кода:

def xml = """<tag id="root">
            |  <tag id="foo" other="blah" more="meh">
            |    <tag id="bar" other="huh"/>
            |  </tag>
            |</tag>""".stripMargin()

def root = new XmlSlurper().parseText(xml)

// Some magic here.

println groovy.xml.XmlUtil.serialize(root)

Я хочу получить следующее:

<root>
  <foo>
    <bar/>
  </foo>
</root>

(Я пишу тестовые утверждения на XML и хочу упростить структуру для них.) Я читал обновление XML с помощью XmlSlurper и искал вокруг, но не нашел с replaceNode() или replaceBody() для обмена узлом при сохранении его дочерних элементов.

1 ответов


добавление "магии" в код в вопросе дает:

def xml = """<tag id="root">
            |  <tag id="foo" other="blah" more="meh">
            |    <tag id="bar" other="huh"/>
            |  </tag>
            |</tag>""".stripMargin()

def root = new XmlSlurper().parseText(xml)

root.breadthFirst().each { n ->
  n.replaceNode { 
    "${n.@id}"( n.children() )
  }
}

println groovy.xml.XmlUtil.serialize(root)

, который печатает:

<?xml version="1.0" encoding="UTF-8"?><root>
  <foo>
    <bar/>
  </foo>
</root>

однако это приведет к удалению любого содержимого в узлах. Чтобы поддерживать контент, нам, вероятно, придется использовать рекурсию и XmlParser для создания нового документа из существующего... Я подумаю

более общее решение

Я думаю, что это более обобщенно:

import groovy.xml.*

def xml = """<tag id="root">
            |  <tag id="foo" other="blah" more="meh">
            |    <tag id="bar" other="huh">
            |      something
            |    </tag>
            |    <tag id="bar" other="huh">
            |      something else
            |    </tag>
            |    <noid>woo</noid>
            |  </tag>
            |</tag>""".stripMargin()

def root = new XmlParser().parseText( xml )

def munge( builder, node ) {
  if( node instanceof Node && node.children() ) {
    builder."${node.@id ?: node.name()}" {
      node.children().each {
        munge( builder, it )
      }
    }
  }
  else {
    if( node instanceof Node ) {
      "${node.@id ?: node.name()}"()
    }
    else {
      builder.mkp.yield node
    }
  }
}

def w = new StringWriter()
def builder = new MarkupBuilder( w )
munge( builder, root )

println XmlUtil.serialize( w.toString() )

и принты:

<?xml version="1.0" encoding="UTF-8"?><root>
  <foo>
    <bar>something</bar>
    <bar>something else</bar>
    <noid>woo</noid>
  </foo>
</root>

сейчас проходит через узлы без (или пустые)id атрибуты