开发者

Groovy:GPath - reading a xml file in which a node attribute is a map

开发者 https://www.devze.com 2023-01-19 02:59 出处:网络
I have following xml file: <doc_xml> <nodes> <node id=\'1\' spec=\"{spec_a=0.9, spec_b=0.1}\" />

I have following xml file:

<doc_xml>
<nodes>
  <node id='1' spec="{spec_a=0.9, spec_b=0.1}" />
  <node id='2' spec="{spec_a=0.1, spec_b=0.3}" />
  <node id='3' spec="{}" />
</nodes>
</doc_xml>

This code was created using Groovy MarkupBuilder.

Now I would like to parse this file in a groovy script:

def xml = new XmlParser().parseText(getDocXmlAsString());

xml.nodes.node.each {
   Map spec = it.@spec; // here I got an exception org.codehaus.groovy.r开发者_StackOverflow社区untime.typehandling.GroovyCastException

}

but I keep getting this exception:

org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '{spec_a=0.9, spec_b=0.1}' with class 'java.lang.String' to class 'java.util.Map'

My question, how to parse an xml attribute which is a map?


I suspect the code and xml you posted are not the actual code and xml you are having troubles with...

However, assuming you meant to close the <node/> tags when posting your example xml, I tried this Groovy code:

def xmlStr = """<doc_xml>
<nodes>
  <node id='1' spec="{spec_a=0.9, spec_b=0.1}"/>
  <node id='2' spec="{spec_a=0.1, spec_b=0.3}"/>
  <node id='3' spec="{}"/>
</nodes>
</doc_xml>"""

def xml = new XmlParser().parseText( xmlStr )
def spec = [:]

xml.nodes.node.each {
  spec = it.@spec
  println spec
}

And it works, and prints out:

{spec_a=0.9, spec_b=0.1}
{spec_a=0.1, spec_b=0.3}
{}

These are Strings, not Maps as you seem to want...

To get them as Maps, you could do:

xml.nodes.node.each {
  spec = Eval.me( it.@spec.tr( '{=}', '[:]' ) )
  println spec
}

You need the tr call, to convert the format you have chosen for your maps into a format groovy can handle...

As you say you generate the XML, can I suggest you change your xml to:

<doc_xml>
<nodes>
  <node id='1' spec="[spec_a:0.9, spec_b:0.1]"/>
  <node id='2' spec="[spec_a:0.1, spec_b:0.3]"/>
  <node id='3' spec="[:]"/>
</nodes>
</doc_xml>

As then, you can skip the tr() step...or use Json or something other than your bespoke format?

Not sure storing a map in an attribute is a good way forward...it feels a little bit brittle to me :-/

EDIT

I see what you mean, it is the Groovy MarkupBuilder adding that strange formating when it adds an attribute as a Map...

Maybe one solution would be to do something like this?

import groovy.xml.MarkupBuilder

// Imaginary data that we're going to generate our XML from:
def nodeData = [
  [ id:1, spec_a:0.9, spec_b:0.1 ],
  [ id:2, spec_a:0.1, spec_b:0.3 ],
  [ id:3 ]
]

def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.doc_xml() {
  nodes() {
    nodeData.each {
      node( it )
    }
  }
}

def xmlStr = writer.toString()

println "Write out the XML"
println xmlStr

def xmlParse = new XmlParser().parseText( xmlStr )
def spec = [:]

println "Write out the Attributes for each node"
xmlParse.nodes.node.each {
  spec = it.attributes()
  println spec
}

That would output:

Write out the XML
<doc_xml>
  <nodes>
    <node id='1' spec_a='0.9' spec_b='0.1' />
    <node id='2' spec_a='0.1' spec_b='0.3' />
    <node id='3' />
  </nodes>
</doc_xml>
Write out the Attributes for each node
[id:1, spec_a:0.9, spec_b:0.1]
[id:2, spec_a:0.1, spec_b:0.3]
[id:3]

As you can see, each map entry is added as an attribute, and these can be extracted back out using the attributes() call on each Node class from the XmlParser

0

精彩评论

暂无评论...
验证码 换一张
取 消