When answering this question How to read values from XML Request and write into XML Response using Groovy? related to namespaces (SOAP) with XmlSlurper
and XmlParser
, I realized that I was actually not able to tell if they are non-namespace-aware by default.
While documentation says so (non-namespace-aware by default):
XmlSlurper ()
Creates a non-validating and non-namespace-aware XmlSlurper which does not allow DOCTYPE declarations in documents.
XmlParser ()
Creates a non-validating and non-namespace-aware XmlParser which does not allow DOCTYPE declarations in documents.
Code is exactly the opposite (namespace-aware by default):
public XmlSlurper() throws ParserConfigurationException, SAXException {
this(false, true);
}
public XmlParser() throws ParserConfigurationException, SAXException {
this(false, true);
}
I found also this answer claiming that XMLSlurper is non-namespace aware by default.
答案 0 :(得分:2)
I think that documentation is wrong and XmlSlurper
and XmlParser
are namespace-aware by default:
def text = '''<person xmlns:city="http://localhost/">
<name>jalopaba</name>
<city:name>Valladolid</city:name>
</person>'''
// XmlSlurper is namespace aware, since new XmlSlurper() --> new XmlSlurper(false, true)
def slurped_person = new XmlSlurper().parseText(text)
assert 'jalopabaValladolid' == slurped_person.name.text() // :name and :name from city
assert 'jalopaba' == slurped_person.':name'.text() // aware of default namespace
assert '' == slurped_person.'city:name'.text() // city namespace not declared
// but you need to make the resulting GPathResult aware of the concrete namespace
slurped_person = new XmlSlurper().parseText(text).declareNamespace([city: 'http://localhost/'])
assert 'jalopabaValladolid' == slurped_person.name.text() // :name and :name from city
assert 'jalopaba' == slurped_person.':name'.text() // aware of default namespace
assert 'Valladolid' == slurped_person.'city:name'.text() // city namespace declared
// If you make XmlSlurper not namespace aware, it uses the whole element string
slurped_person = new XmlSlurper(false, false).parseText(text)
assert 'jalopaba' == slurped_person.name.text() // just element 'name'
assert '' == slurped_person.':name'.text() // not aware of default namespace
assert 'Valladolid' == slurped_person.'city:name'.text() // using the whole element string (it seems to be namespace aware, but it's not)
// And when it is not namespace aware, nothing changes declaring namespaces
slurped_person = new XmlSlurper(false, false).parseText(text).declareNamespace([city: 'http://localhost/'])
assert 'jalopaba' == slurped_person.name.text() // just element 'name'
assert '' == slurped_person.':name'.text() // not aware of default namespace
assert 'Valladolid' == slurped_person.'city:name'.text() // using the whole element string (it seems to be namespace aware, but it's not)
def c = new Namespace('http://localhost/', 'city')
assert c.name instanceof QName // => new QName('http://localhost/', 'name', 'city')
// XmlParser is namespace aware, since new XmlParser() --> new XmlParser(false, true)
def parsed_person = new XmlParser().parseText(text)
assert parsed_person.toString() == 'person[attributes={}; value=[name[attributes={}; value=[jalopaba]], {http://localhost/}name[attributes={}; value=[Valladolid]]]]'
assert 'jalopaba' == parsed_person.name.text() // default namespace
assert 'jalopaba' == parsed_person[new QName('name')].text() // default namespace
assert 'jalopabaValladolid' == parsed_person[new QName('http://localhost/', 'name')].text() // aware of namespace and empty string as prefix
assert 'Valladolid' == parsed_person[new QName('http://localhost/', 'name', 'it_does_not_matter')].text() // aware of namespace, prefix does not matter
assert '' == parsed_person[new QName('http://wrong_namespace/', 'name', 'city')].text() // aware of namespace, wrong URI with good prefix gets nothing
assert 'Valladolid' == parsed_person[c.name].text()
assert 'Valladolid' == parsed_person.'city:name'.text() // using the whole element string
// With XmlParser not namespace aware...
parsed_person = new XmlParser(false, false).parseText(text)
assert parsed_person.toString() == 'person[attributes={xmlns:city=http://localhost/}; value=[name[attributes={}; value=[jalopaba]], city:name[attributes={}; value=[Valladolid]]]]'
assert 'jalopaba' == parsed_person.name.text()
assert 'jalopaba' == parsed_person[new QName('name')].text()
assert 'jalopaba' == parsed_person[new QName('http://localhost/', 'name')].text() // ignores namespace, only uses 'name' string
assert '' == parsed_person[new QName('http://localhost/', 'name', 'wrong_prefix')].text() // not aware of namespace, the only important thing is prefix
assert 'Valladolid' == parsed_person[new QName('http://wrong_namespace/', 'name', 'city')].text() // wrong namespace but not aware, the only important thing is prefix
assert 'Valladolid' == parsed_person[c.name].text()
assert 'Valladolid' == parsed_person.'city:name'.text()
答案 1 :(得分:1)
从Groovy 2.4.6开始,文档错误:
/**
* Creates a non-validating and non-namespace-aware <code>XmlSlurper</code> which does not allow DOCTYPE declarations in documents.
*
* @throws ParserConfigurationException if no parser which satisfies the requested configuration can be created.
* @throws SAXException for SAX errors.
*/
public XmlSlurper() throws ParserConfigurationException, SAXException {
this(false, true);
}
它实际上创建了一个名称空间感知解析器(第二个参数为true)。
我还报告了一个错误,其中名称空间前缀未正确处理:https://issues.apache.org/jira/browse/GROOVY-7781。幸运的是,另一位用户发布了PR来修复。有人应该用PR来解决文档问题,这会多次给自己和他人造成混淆。