Groovy - XML Tree遍历使用*作为语法糖的breadthFirst()方法

时间:2017-03-23 19:50:36

标签: xml groovy xml-parsing

处理XML部分中的Groovy documentation提到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()。这是预期的行为还是我错过了文档中的内容?

1 个答案:

答案 0 :(得分:1)

我认为文档并未强调*实际上是一种速记,只能获取调用它的节点的直接子节点。撰写本文时的文档示例如下:

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的指定属性。   实现以下快捷方式:

     
      {li> '..' parent()   {li> '*' children()   {li> '**' depthFirst()   
  • '@'用于属性访问
  •   

我创建了this pull request来修复它。