【问题标题】:No closing tags while building xml file with MarkupBuilder使用 MarkupBuilder 构建 xml 文件时没有结束标签
【发布时间】:2018-01-09 10:46:56
【问题描述】:

我想在我的 Jenkins-Pipeline-Job 中使用 Groovy 来构建我的 Jenkins Slave 和已安装节点的状态列表。因此,我有一些应该以 xml 显示的列表。在使用 IntelliJ 进行测试时,我编写了以下代码。

import groovy.xml.MarkupBuilder

def listNodeNames = []
listNodeNames << 'SLAVE1_NODE_1'
listNodeNames << 'SLAVE1_NODE_2'
listNodeNames << 'SLAVE2_NODE_1'
listNodeNames << 'SLAVE2_NODE_2'


def listComputerNames = []
listComputerNames << 'SLAVE1'
listComputerNames << 'SLAVE2'

def stringWriter = new StringWriter()
def xmlBuilder = new MarkupBuilder(stringWriter)

xmlBuilder.computers {
    for (i = 0; i < listComputerNames.size(); i++){

        xmlBuilder.computer {
            xmlBuilder.computerName("${listComputerNames[i]}")
            xmlBuilder.computerStatus("online")

            for (j = 0; j < listNodeNames.size(); j++){
                if (listNodeNames[j].contains(listComputerNames[i])){
                    xmlBuilder.slave {
                        xmlBuilder.slaveName("${listNodeNames[j]}")
                        xmlBuilder.slaveStatus('test')
                        xmlBuilder.slaveReason('test')
                    }
                }
            }
        }

    }
}

def xml = stringWriter.toString()
println xml

只要我在 IntelliJ 中运行代码,一切正常,我得到一个有效的 xml 文件:

  <computers>
      <computer>
        <computerName>SLAVE1</computerName>
        <computerStatus>online</computerStatus>
        <slave>
          <slaveName>SLAVE1_NODE1</slaveName>
          <slaveStatus>test</slaveStatus>
          <slaveReason>test</slaveReason>
        </slave>
        <slave>
          <slaveName>SLAVE1_NODE2</slaveName>
          <slaveStatus>test</slaveStatus>
          <slaveReason>test</slaveReason>
        </slave>
      </computer>
      <computer>
        <computerName>SLAVE2</computerName>
        <computerStatus>online</computerStatus>
        <slave>
          <slaveName>SLAVE2_NODE1</slaveName>
          <slaveStatus>test</slaveStatus>
          <slaveReason>test</slaveReason>
        </slave>
        <slave>
          <slaveName>SLAVE2_NODE2</slaveName>
          <slaveStatus>test</slaveStatus>
          <slaveReason>test</slaveReason>
        </slave>
      </computer>
    </computers>

但如果我在我的 Jenkins 实例上执行相同的脚本,大多数结束标签都会丢失:

<computers>
  <computer>
    <computerName>SLAVE1</computerName>
    <computerStatus>online</computerStatus>
    <slave>
      <slaveName>SLAVE1_NODE1</slaveName>
      <slaveStatus>test</slaveStatus>
      <slaveReason>test</slaveReason>
      <slave>
        <slaveName>SLAVE1_NODE2</slaveName>
        <slaveStatus>test</slaveStatus>
        <slaveReason>test</slaveReason>
        <computer>
          <computerName>SLAVE2</computerName>
          <computerStatus>online</computerStatus>
          <slave>
            <slaveName>SLAVE2_NODE1</slaveName>
            <slaveStatus>test</slaveStatus>
            <slaveReason>test</slaveReason>
            <slave>
              <slaveName>SLAVE2_NODE2</slaveName>
              <slaveStatus>test</slaveStatus>
              <slaveReason>test</slaveReason>

在通过 jenkins 创建 xml 文件时我做错了什么还是有具体的步骤要做?

【问题讨论】:

    标签: xml jenkins groovy jenkins-pipeline


    【解决方案1】:

    我想通了。我真的不明白为什么,但 MarkupBuilderhast du 被封装在 @nonCPSmarked 方法中。如果我调用此方法,jenkins 将按预期执行。

    @nonCPS
    def buildXml(list1, list2){
        //generate xml from lists
    }
    
    buildXml(list1, list2)
    

    【讨论】:

      【解决方案2】:

      这真的很奇怪。

      你可以试试下面看看是否有帮助。

      def listNodeNames = ['SLAVE1_NODE_1', 'SLAVE1_NODE_2', 'SLAVE2_NODE_1', 'SLAVE2_NODE_2']
      
      def listComputerNames = ['SLAVE1', 'SLAVE2']
      
      def xml = new groovy.xml.StreamingMarkupBuilder().bind {
          computers {
            listComputerNames.collect { cn ->
                computer {
                   computerName(cn)
                   computerStatus('online')
                   listNodeNames.collect { slv ->
                      if (slv.startsWith(cn)){
                         slave {
                           slaveName(slv)
                           slaveStatus('test')
                           slaveReason('test')
                         }
                      }
                   }
                }
            }
          }
      }
      
      println groovy.xml.XmlUtil.serialize(xml)
      

      【讨论】:

      • 使用你的代码我得到一个java.lang.NoSuchMethodError: No such DSL method 'computers' found among steps [acceptGitLabMR, addGitLabMRComment, archive, bat, build, catchError, checkout, deleteDir, dir, dockerFingerprintFrom, dockerFingerprintRun [,,,] 错误。在我的版本中,我能够解决这个问题,同时在每个节点声明前添加 xmlBuilder.。 (使用 IntelliJ 并通过 groovy.bat 命令构建它可以正常工作)
      • 顺便说一句,您可以尝试在上述解决方案中将每个节点名称包裹在单引号' 之间,看看是否有帮助。
      • 演示的代码不是与您答案中的代码相同吗?即使使用',我也会收到java.lang.NoSuchMethodError: No such DSL method 'computers' 消息。这真的很奇怪,,,
      • 相同。只是为了了解代码在普通的 groovy 中按预期工作。詹金斯真的没有声音。
      • 我认为这一定是一个詹金斯错误。如果我删除所有 berween xmlBuilder.computer { } 输出给我:[Pipeline] echo &lt;computers [Pipeline] End of Pipeline 即使我添加更多条目,最后一个开始标签总是“损坏”
      【解决方案3】:

      使用函数 nodeCompleted('','computers') 来解决这个问题

      import groovy.xml.MarkupBuilder
      
      def listNodeNames = []
      listNodeNames << 'SLAVE1_NODE_1'
      listNodeNames << 'SLAVE1_NODE_2'
      listNodeNames << 'SLAVE2_NODE_1'
      listNodeNames << 'SLAVE2_NODE_2'
      
      
      def listComputerNames = []
      listComputerNames << 'SLAVE1'
      listComputerNames << 'SLAVE2'
      
      def stringWriter = new StringWriter()
      def xmlBuilder = new MarkupBuilder(stringWriter)
      
      xmlBuilder.computers {
          for (i = 0; i < listComputerNames.size(); i++){
      
              xmlBuilder.computer {
                  xmlBuilder.computerName("${listComputerNames[i]}")
                  xmlBuilder.computerStatus("online")
      
                  for (j = 0; j < listNodeNames.size(); j++){
                      if (listNodeNames[j].contains(listComputerNames[i])){
                          xmlBuilder.slave {
                              xmlBuilder.slaveName("${listNodeNames[j]}")
                              xmlBuilder.slaveStatus('test')
                              xmlBuilder.slaveReason('test')
                          }
                          nodeCompleted('computers','slave')
                      }
                  }
              }
              nodeCompleted('','computers')
      
          }
      }
      
      def xml = stringWriter.toString()
      println xml
      

      【讨论】:

        猜你喜欢
        • 2013-02-03
        • 1970-01-01
        • 1970-01-01
        • 2015-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-28
        • 2011-09-06
        相关资源
        最近更新 更多