【问题标题】:Converting XML to JSON in Groovy在 Groovy 中将 XML 转换为 JSON
【发布时间】:2013-09-20 17:37:53
【问题描述】:

我希望使用 groovy 将 xml 转换为 JSON。我了解转换的细节取决于我的偏好,但是有人可以推荐我应该使用哪些库和方法,并为我提供一些关于为什么/如何使用它们的信息吗?我正在使用 groovy,因为有人告诉我它是一个非常有效的解析器,所以我正在寻找可以利用它的库

谢谢!

【问题讨论】:

    标签: xml json groovy converter


    【解决方案1】:

    我参加聚会有点晚了,但以下代码会将任何 XML 转换为一致的 JSON 格式:

    def toJsonBuilder(xml){
        def pojo = build(new XmlParser().parseText(xml))
        new groovy.json.JsonBuilder(pojo)
    }
    def build(node){
        if (node instanceof String){ 
            return // ignore strings...
        }
        def map = ['name': node.name()]
        if (!node.attributes().isEmpty()) {
            map.put('attributes', node.attributes().collectEntries{it})
        }
        if (!node.children().isEmpty() && !(node.children().get(0) instanceof String)) { 
            map.put('children', node.children().collect{build(it)}.findAll{it != null})
        } else if (node.text() != ''){
            map.put('value', node.text())
        }
        map
    }
    toJsonBuilder(xml1).toPrettyString()
    

    转换 XML...

    <root>
        <node>Tim</node>
        <node>Tom</node>
    </root>
    

    进入...

    {
        "name": "root",
        "children": [
            {
                "name": "node",
                "value": "Tim"
            },
            {
                "name": "node",
                "value": "Tom"
            }
        ]
    }
    

    欢迎反馈/改进!

    【讨论】:

      【解决方案2】:

      这样就可以了:http://www.json.org/java/

      在撰写此答案时,该 jar 可在以下位置获得:http://mvnrepository.com/artifact/org.json/json/20140107

      下面是用法。


      进口:

      import org.json.JSONObject
      import org.json.XML
      

      转化率:

      static String convert(final String input) {
        int textIndent = 2
        JSONObject xmlJSONObj = XML.toJSONObject(input)
        xmlJSONObj.toString(textIndent)
      }
      

      相关的 Spock 测试显示我们需要注意的某些场景:

      void "If tag and content are available, the content is put into a content attribute"() {
        given:
        String xml1 = '''
        <tag attr1="value">
          hello
        </tag>
        '''
        and:
        String xml2 = '''
        <tag attr1="value" content="hello"></tag>
        '''
        and:
        String xml3 = '''
        <tag attr1="value" content="hello" />
        '''
        and:
        String json = '''
        {"tag": {
            "content": "hello",
            "attr1": "value"
        }}
        '''
      
        expect:
        StringUtils.deleteWhitespace(convert(xml1)) == StringUtils.deleteWhitespace(json)
        StringUtils.deleteWhitespace(convert(xml2)) == StringUtils.deleteWhitespace(json)
        StringUtils.deleteWhitespace(convert(xml3)) == StringUtils.deleteWhitespace(json)
      }
      
      void "The content attribute would be merged with the content as an array"() {
        given:
        String xml = '''
        <tag content="same as putting into the content"
             attr1="value">
          hello
        </tag>
        '''
        and:
        String json = '''
        {"tag": {
            "content": [
                "same as putting into the content",
                "hello"
            ],
            "attr1": "value"
        }}
        '''
      
        expect:
        StringUtils.deleteWhitespace(convert(xml)) == StringUtils.deleteWhitespace(json)
      }
      
      void "If no additional attributes, the content attribute would be omitted, and it creates array in array instead"() {
        given:
        String xml = '''
        <tag content="same as putting into the content" >
          hello
        </tag>
        '''
        and:
        String notExpected = '''
        {"tag": {[
                "same as putting into the content",
                "hello"
                ]}
        }
        '''
        String json = '''
        {"tag": [[
                "same as putting into the content",
                "hello"
                ]]
        }
        '''
      
        expect:
        StringUtils.deleteWhitespace(convert(xml)) != StringUtils.deleteWhitespace(notExpected)
        StringUtils.deleteWhitespace(convert(xml)) == StringUtils.deleteWhitespace(json)
      }
      

      希望这对仍然需要解决此问题的任何人有所帮助。

      【讨论】:

      • 超级简单,几行代码。它还处理 XML 属性。
      【解决方案3】:

      我利用 staxon 将复杂的 XML 转换为 JSON。这包括带有属性的元素。

      下面是xml转json的例子。

      https://github.com/beckchr/staxon/wiki/Converting-XML-to-JSON

      【讨论】:

        【解决方案4】:

        您可以使用基本的 Groovy 完成所有操作:

        // Given an XML string
        def xml = '''<root>
                    |    <node>Tim</node>
                    |    <node>Tom</node>
                    |</root>'''.stripMargin()
        
        // Parse it
        def parsed = new XmlParser().parseText( xml )
        
        // Convert it to a Map containing a List of Maps
        def jsonObject = [ root: parsed.node.collect {
          [ node: it.text() ]
        } ]
        
        // And dump it as Json
        def json = new groovy.json.JsonBuilder( jsonObject )
        
        // Check it's what we expected
        assert json.toString() == '{"root":[{"node":"Tim"},{"node":"Tom"}]}'
        

        但是,你确实需要考虑某些事情......

        • 您将如何表示属性?
        • 您的 XML 是否包含 &lt;node&gt;text&lt;another&gt;woo&lt;/another&gt;text&lt;/node&gt; 样式标记?如果是这样,您将如何处理?
        • CDATA?注释?等等?

        两者之间并不是一个平滑的 1:1 映射...但是对于给定的特定格式的 XML,也许可以想出给定的特定格式的 Json。

        更新:

        要从文档中获取名称(见评论),您可以:

        def jsonObject = [ (parsed.name()): parsed.collect {
          [ (it.name()): it.text() ]
        } ]
        

        更新 2

        您可以通过以下方式添加对更大深度的支持:

        // Given an XML string
        def xml = '''<root>
                    |    <node>Tim</node>
                    |    <node>Tom</node>
                    |    <node>
                    |      <anotherNode>another</anotherNode>
                    |    </node>
                    |</root>'''.stripMargin()
        
        // Parse it
        def parsed = new XmlParser().parseText( xml )
        
        // Deal with each node:
        def handle
        handle = { node ->
          if( node instanceof String ) {
              node
          }
          else {
              [ (node.name()): node.collect( handle ) ]
          }
        }
        // Convert it to a Map containing a List of Maps
        def jsonObject = [ (parsed.name()): parsed.collect { node ->
           [ (node.name()): node.collect( handle ) ]
        } ]
        
        // And dump it as Json
        def json = new groovy.json.JsonBuilder( jsonObject )
        
        // Check it's what we expected
        assert json.toString() == '{"root":[{"node":["Tim"]},{"node":["Tom"]},{"node":[{"anotherNode":["another"]}]}]}'
        

        再一次,所有之前的警告仍然适用(但此时应该听到更响亮的声音);-)

        【讨论】:

        • 非常感谢您的帮助!但是,我对您的解决方案还有一个问题.. 当您定义 jsonObject 时,您指定了“root:”和“node:”,有没有一种方法可以让 groovy 通过分析名称自动指定这些名称而无需假设xml 属性?
        • @TomHadkiss 更新了答案以展示如何做到这一点(但同样,对于更复杂的 xml 文档,事情会变得很奇怪);-)
        • 抱歉,谷歌没有为我提供任何答案。您如何建议使用更深入的 XML?例如,another
        • @TomHadkiss 已更新,但您应该再次听到警报,因为我们正在通过这种通用转换走到尽头
        猜你喜欢
        • 1970-01-01
        • 2021-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多