【问题标题】:Are XmlParser and XmlSlurper namespace aware by default?默认情况下是否支持 XmlParser 和 XmlSlurper 命名空间?
【发布时间】:2016-01-29 20:47:00
【问题描述】:

当用XmlSlurperXmlParser 回答这个与命名空间 (SOAP) 相关的问题 How to read values from XML Request and write into XML Response using Groovy? 时,我意识到我实际上无法判断它们是否非命名空间感知默认情况下。

虽然文档这么说(默认情况下不支持命名空间):

XmlSlurper

XmlSlurper()

创建一个非验证和非命名空间感知 XmlSlurper 不允许在文档中声明 DOCTYPE。

XmlParser

XmlParser()

创建一个非验证和非命名空间感知 不允许在文档中声明 DOCTYPE 的 XmlParser。

代码正好相反(默认命名空间感知):

XmlSlurper:

public XmlSlurper() throws ParserConfigurationException, SAXException {
    this(false, true);
}

XmlParser:

public XmlParser() throws ParserConfigurationException, SAXException {
    this(false, true);
}

我还发现这个 answer 声称 XMLSlurper 默认情况下是非命名空间感知的。

【问题讨论】:

    标签: xml groovy namespaces


    【解决方案1】:

    我认为文档是错误的,XmlSlurperXmlParser 默认是 namespace-aware

    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()
    

    【讨论】:

      【解决方案2】:

      从 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 来解决文档问题,因为这多次给我自己和其他人造成了困惑。

      【讨论】:

        猜你喜欢
        • 2020-05-06
        • 2015-06-04
        • 2015-05-28
        • 1970-01-01
        • 2012-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-11
        相关资源
        最近更新 更多