【问题标题】:Recursively enable children nodes xml groovy递归启用子节点xml groovy
【发布时间】:2018-05-21 12:11:35
【问题描述】:

我有以下 xml 文件:

<testItems>
<children>
<testItem name=TestSuite1 enabled=false>
    <children>
        <testItem name=test1 enabled=false>
        </testItem>
        <testItem name=test2 enabled=false>
        </testItem>
        <testItem name=test3 enabled=false>
        </testItem>
    </children>
</testItem>
<testItem name=TestSuite2 enabled=false>
    <children>
        <testItem name=test3 enabled=false>
        </testItem>
        <testItem name=test4 enabled=false>
        </testItem>
        <testItem name=test5 enabled=false>
        </testItem>
    </children>
</testItem>

结构可以改变(意味着树的深度可以改变)。

我想启用 TestSuite1 并通过递归启用 TestSuite1 的所有子项(test1、test2、test3)

到目前为止,我有:

def root = new XmlParser(false, false, true).parse(mdsFile)

 root.depthFirst().each {
                if (it.@name == testItemToEnable) {
                    it.@enabled = true
                    it.children.depthFirst().each { child ->
                    child.@enabled = true
                }
            }

但我有以下例外:

 No signature of method: groovy.util.NodeList.depthFirst() is applicable for argument types: () values: []

[在评论中的问题后添加]

<testItems>
<children>
<testItem name="TestSuite1" enabled="false">
  <children>
    <testItem name="test1" enabled="false">
    </testItem>
    <testItem name="test2" enabled="false">
    <children>
        <testItem name="testX" enabled="false">
    </testItem>
    </children>
    </testItem>
    <testItem name="test3" enabled="false">
    </testItem>
  </children>
</testItem>
<testItem name="TestSuite2" enabled="false">
  <children>
    <testItem name="test3" enabled="false">
    </testItem>
    <testItem name="test4" enabled="false">
    </testItem>
    <testItem name="test5" enabled="false">
    </testItem>
  </children>
</testItem>

场景: 1. suiteToEnable='test1' => test1, TestSuite1 变为真

  1. suiteToEnable='testX' => testX、test2 和 TestSuite1 变为 true

【问题讨论】:

    标签: java xml groovy xml-parsing


    【解决方案1】:

    [澄清评论后修改]

    以下代码将启用的属性设置为 true 并打印出结果字符串:

    import groovy.xml.*
    
    def str = '''\
    <testItems>
      <children>
        <testItem name="TestSuite1" enabled="false">
          <children>
            <testItem name="test1" enabled="false">
            </testItem>
            <testItem name="test2" enabled="false">
            </testItem>
            <testItem name="test3" enabled="false">
            </testItem>
          </children>
        </testItem>
        <testItem name="TestSuite2" enabled="false">
          <children>
            <testItem name="test3" enabled="false">
            </testItem>
            <testItem name="test4" enabled="false">
            </testItem>
            <testItem name="test5" enabled="false">
            </testItem>
          </children>
        </testItem>
      </children>
    </testItems>'''
    
    def xml = new XmlSlurper().parseText(str)
    
    def suiteToEnable = 'TestSuite2'
    
    xml.'**'.find { 
      it.name() == 'testItem' && it.@name == suiteToEnable
    }.'**'.findAll { 
      it.name() == 'testItem'
    }*.@enabled = 'true'
    
    println XmlUtil.serialize(xml)
    

    输出:

    <?xml version="1.0" encoding="UTF-8"?><testItems>
      <children>
        <testItem name="TestSuite1" enabled="false">
          <children>
            <testItem name="test1" enabled="false"/>
            <testItem name="test2" enabled="false"/>
            <testItem name="test3" enabled="false"/>
          </children>
        </testItem>
        <testItem name="TestSuite2" enabled="true">
          <children>
            <testItem name="test3" enabled="true"/>
            <testItem name="test4" enabled="true"/>
            <testItem name="test5" enabled="true"/>
          </children>
        </testItem>
      </children>
    </testItems>
    

    这使用了 groovy depthFirst alias **spread operator *.

    [评论中问题后的附录]

    对于您的第二个问题,我们可以只启用一个孩子及其祖父母:

    def xml = new XmlSlurper().parseText(str)
    
    def suiteToEnable = 'test2'
    
    def item = xml.'**'.find { 
      it.name() == 'testItem' && it.@name == suiteToEnable
    }
    item.@enabled = 'true'
    item.parent().parent().@enabled = 'true'
    
    println XmlUtil.serialize(xml)
    

    打印:

    <?xml version="1.0" encoding="UTF-8"?><testItems>
      <children>
        <testItem name="TestSuite1" enabled="true">
          <children>
            <testItem name="test1" enabled="false"/>
            <testItem name="test2" enabled="true"/>
            <testItem name="test3" enabled="false"/>
          </children>
        </testItem>
        <testItem name="TestSuite2" enabled="false">
          <children>
            <testItem name="test3" enabled="false"/>
            <testItem name="test4" enabled="false"/>
            <testItem name="test5" enabled="false"/>
          </children>
        </testItem>
      </children>
    </testItems>
    

    [cmets中另一个问题后的附录2]

    以下代码首先找到一个特定的节点,然后将元素名称为testItem的所有父节点设置为enabled="true"

    def xml = new XmlSlurper().parseText(str)
    def suiteToEnable = 'testX'
    
    // first find our target node
    def item = xml.'**'.find { 
      it.name() == 'testItem' && it.@name == suiteToEnable
    }
    
    // then get the parents recursively, find all parents called
    // 'testItem' and set them to enabled = 'true'
    getParents(item).findAll { it.name() == 'testItem' }.each { 
      it.@enabled = 'true' 
    }
    
    println XmlUtil.serialize(xml)
    
    // recursively get parents of node using the '..' alias for 
    // the node.parent() call
    def getParents(node) {
      (node.is(node.'..') ? [] : getParents(node.'..')) + [node]
    }
    

    打印出来:

    <testItems>
      <children>
        <testItem name="TestSuite1" enabled="true">
          <children>
            <testItem name="test1" enabled="false"/>
            <testItem name="test2" enabled="true">
              <children>
                <testItem name="testX" enabled="true"/>
              </children>
            </testItem>
            <testItem name="test3" enabled="false"/>
          </children>
        </testItem>
        <testItem name="TestSuite2" enabled="false">
          <children>
            <testItem name="test3" enabled="false"/>
            <testItem name="test4" enabled="false"/>
            <testItem name="test5" enabled="false"/>
          </children>
        </testItem>
      </children>
    </testItems>
    

    【讨论】:

    • 没有按预期工作,这只是启用/禁用所有测试项目。我希望,当给定一个测试项目名称时,我启用它及其所有子项,例如parameterGiven=TestSuite1 => TestSuite1, test1,test2,test3 为真,其他均为假
    • 我的错,我已经修复了解决方案以更好地匹配问题
    • 您认为我可以修改您的代码以启用套件的父母吗?例如,如果 suiteToEnable = test2 我希望 test2 为真,并且 TestSuite1(其父级)为真。
    • @GeorgeCimpoies 我添加了第二个代码 sn-p 根据您的最后评论进行选择性的子祖父母修改。
    • 我知道我已经越界了,我无法表达我对你的帮助的感激之情,但你认为你可以修改最后一个 sn-p 来为无限数量的父母工作吗?假设 test2 有一个 testItem 子 testX 并且 suiteToEnable='testX' => testX,test2 和 TestSuite1 变为 3。但是,如果 suiteToEnable='test1',只有 test1 和 TestSuite1 变为 true。我将在问题中添加另一个 xml sn-p。再次感谢您的帮助!
    猜你喜欢
    • 2017-10-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    • 2011-05-15
    • 1970-01-01
    相关资源
    最近更新 更多