使用Groovy中Map的属性和子节点动态生成XML

时间:2018-02-09 16:09:39

标签: xml groovy

给定一个不确定深度的Groovy Map,每个级别都具有"属性"和"元素"关键,我正在寻找一种从这张地图递归构建XML的方法:

       Map map = [
            root: [
                    elements  : [
                            node1: [
                                    elements  : [
                                            key1Node1: "elementValue1Node1",
                                            key2Node1: "elementValue2Node2",
                                    ],
                                    attributes: [
                                            attribute1Node1: "attributeValue1node1",
                                            attribute2Node1: "attributeValue2node1",
                                            attribute3Node1: "attributeValue3node1"
                                    ]
                            ],
                            node2: [
                                    elements  : [
                                            key1Node2: "elementValue1Node2",
                                            key2Node2: "elementValue2Node2",
                                    ],
                                    attributes: [
                                            attribute1Node2: "attributeValue1node2",
                                            attribute2Node2: "attributeValue2node2",
                                            attribute3Node2: "attributeValue3node2"
                                    ]
                            ]
                    ],
                    attributes: [
                            rootAttribute: "iniciarSesion"
                    ]
            ]

    ]

生成的XML应如下所示:

<root rootAttribute="rootValue">
    <node1 attribute1Node1="attributeValue1node1" attribute2Node1="attributeValue2node1" attribute3Node1="attributeValue3node1">
        <key1Node1>elementValue1Node1</key1Node1>
        <key2Node1>elementValue2Node2</key2Node1>
    </node1>
    <node2 attribute1Node1="attributeValue1node2" attribute2Node1="attributeValue2node2" attribute3Node1="attributeValue3node2">
        <key1Node2>elementValue1Node2"</key1Node2>
        <key2Node2>elementValue2Node2</key2Node2>
    </node2>
</root>

到目前为止,我已经尝试过使用一种方法,该方法可以遍历对象并在每个回合中添加必要的节点。 Groovy documentation for markupBuilder表明createNode方法可以获取属性的映射和值的对象。所以我尝试了以下方法:

static def makeXmlBody(map) {
    def writer = new StringWriter()
    def xml = new MarkupBuilder(writer)

    map.each {
        k, v ->
            if (v.getClass() == LinkedHashMap) {
                xml.createNode(k, v.attributes, makeXmlBody(v.elements))
                println(writer)

            } else {
                xml.createNode(k, v)
                println(writer)
            }
    }
}

我们的想法是,如果价值是地图,那么它必须具有&#34;元素&#34;和&#34;属性&#34;在里面。因此,我们可以将字段键作为第一个参数,即节点&#34;属性&#34; map作为第二个,并且递归调用与第三个函数相同的函数,以便构建每个级别。

问题是,似乎每个级别都保持下面的每个级别不变,所以在输出中(参见代码中的两个printlns),我看到每个级别都在正确地完成,但是最终的结果是不是是有用的。

<key1Node1>elementValue1Node1
<key1Node1>elementValue1Node1
  <key2Node1>elementValue2Node2
<node1 attribute1Node1='attributeValue1node1' attribute2Node1='attributeValue2node1' attribute3Node1='attributeValue3node1'>{key1Node1=elementValue1Node1, key2Node1=elementValue2Node2}
<key1Node2>elementValue1Node2
<key1Node2>elementValue1Node2
  <key2Node2>elementValue2Node2
<node1 attribute1Node1='attributeValue1node1' attribute2Node1='attributeValue2node1' attribute3Node1='attributeValue3node1'>{key1Node1=elementValue1Node1, key2Node1=elementValue2Node2}
  <node2 attribute1Node2='attributeValue1node2' attribute2Node2='attributeValue2node2' attribute3Node2='attributeValue3node2'>{key1Node2=elementValue1Node2, key2Node2=elementValue2Node2}
<root rootAttribute='iniciarSesion'>{node1={elements={key1Node1=elementValue1Node1, key2Node1=elementValue2Node2}, attributes={attribute1Node1=attributeValue1node1, attribute2Node1=attributeValue2node1, attribute3Node1=attributeValue3node1}}, node2={elements={key1Node2=elementValue1Node2, key2Node2=elementValue2Node2}, attributes={attribute1Node2=attributeValue1node2, attribute2Node2=attributeValue2node2, attribute3Node2=attributeValue3node2}}}

我在这里做错了什么?

1 个答案:

答案 0 :(得分:0)

好吧,经过几个小时的挣扎,似乎这将进入任何深度的嵌套地图并构建XML。可能不是我看起来最犹太的代码,但它会做。

static def makeXmlBody(map, lastParent, counter) {
    def writer = new StringWriter()
    def xmlBuilder = new MarkupBuilder(writer)
    if (counter == 0) {
        xmlBuilder.mkp.xmlDeclaration(version: "1.0", encoding: "utf-8")
    }
    counter++

    map.each {
        if (it.value.getClass() == LinkedHashMap) {
            xmlBuilder.createNode(it.key, it.value.attributes, makeXmlBody(it.value.elements, lastParent, counter))
            xmlBuilder.nodeCompleted(lastParent, it.key)
            lastParent = it.key
        } else {

            xmlBuilder.createNode(it.key, it.value)
            xmlBuilder.nodeCompleted(lastParent, it.key)
        }
    }
    return StringEscapeUtils.unescapeXml(writer.toString())
}

使用

makeXmlBody(map, null, 0)

输出(美化)

<?xml version='1.0' encoding='utf-8'?>
<root rootAttribute='rootAttribute1'>
    <node1 attribute1Node1='attributeValue1node1' attribute2Node1='attributeValue2node1'
           attribute3Node1='attributeValue3node1'>
        <key1Node1>elementValue1Node1</key1Node1>
        <key2Node1>elementValue2Node2</key2Node1>
    </node1>
    <node2 attribute1Node2='attributeValue1node2' attribute2Node2='attributeValue2node2'
           attribute3Node2='attributeValue3node2'>
        <key1Node2>elementValue1Node2</key1Node2>
        <key2Node2>elementValue2Node2</key2Node2>
    </node2>
</root>