Groovy - XML Tree Traversal widththFirst() 方法使用 * 作为语法糖


处理

XML部分中的Groovy文档提到breadthFirst()*较短语法的同义词。但是,*用法最终只会遍历父节点下的一个级别:

def books = '''
<response>
   <books>
      <book available="20" id="1">
         <title>foo</title>
         <author id="1">foo author</author>
      </book>
      <book available="14" id="2">
         <title>bar</title>
         <author id="2">bar author</author>
      </book>
   </books>
</response>'''
def response = new XmlSlurper().parseText(books)
def bk = response.'*'.find { node ->
   node.name() == 'book' && node['@id'].toInteger() == 2
}
assert bk.empty

而显式使用 breadthFirst() 可以执行我期望两者都要做的事情,即执行广度优先遍历:

def books = '''
<response>
   <books>
      <book available="20" id="1">
         <title>foo</title>
         <author id="1">foo author</author>
      </book>
      <book available="14" id="2">
         <title>bar</title>
         <author id="2">bar author</author>
      </book>
   </books>
</response>'''
def response = new XmlSlurper().parseText(books)
def bk = response.breadthFirst().find { node ->
   node.name() == 'book' && node['@id'].toInteger() == 2
}
assert bk.title == 'bar' // bk is no longer an empty list of children

*语义显然与breadthFirst()不同。这是预期的行为还是我错过了文档中的某些内容?

我认为文档并没有强调*实际上是一个简写,它只获取调用它的节点的直接子级。在撰写本文时,文档中的示例是:

def catcherInTheRye = response.value.books.'*'.find { node->
 /* node.@id == 2 could be expressed as node['@id'] == 2 */
    node.name() == 'book' && node.@id == '2'
}

请注意,他们没有像在自己的示例中那样使用 response.'*'。所以*并不是breadthFirst()的简写(我同意应该审查文档(。它只是意味着直接子节点,而breadthFirst()递归遍历节点。这可以从GPathResult.getProperty的Javadocs中得到证实:

返回此 GPathResult 的指定属性。 实现以下快捷键:

  • parent() '..'
  • '*' children()
  • '**' depthFirst()
  • 属性访问'@'

我创建了这个拉取请求来修复它。

最新更新