Groovy引用带有xpath的xml重复节点值(插值误用?)

时间:2016-06-22 01:00:37

标签: xml xpath groovy soapui interpolation

设置:SOAP UI 5.2.0。,Groovy生成XML的步骤。 我们需要读取一个CSV,其中包含类似XPath的节点位置和要放置样本XML的新值 以下答案中代码的最后一个版本完全符合我们的目标:Groovy replace node values in xml with xpath
只有一个问题: 我们的XML包含重复元素,因为它错误解释了#34; [1]"在Body.GetWeather[1].CityName

    def node = xml
key.split("\\.").each {
  node = node."${it}"
}

理想情况下,我们还需要使用类似Body.GetWeather[CountryName="Africa"].CityName的内容。我也尝试使用XMLParser并尝试语法(见下文)。我是Groovy的新手,我可能会错过一些关于它的东西。 所以,让我知道我是否需要以不同的方式解决问题。

以下是第3个例子中描述的实际问题:

// reading XML
def myInputXML = '''
<soapenv:Envelope   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header/>
  <soapenv:Body>
      <web:GetWeather xmlns:web="http://www.webserviceX.NET">
          <web:CityName>Cairo</web:CityName>
          <web:CountryName>Africa</web:CountryName>
      </web:GetWeather>
      <web:GetWeather xmlns:web="http://www.webserviceX.NET">
          <web:CityName>Heidelberg</web:CityName>
          <web:CountryName>Germany</web:CountryName>
      </web:GetWeather>
      <web:GetWeather xmlns:web="http://www.webserviceX.NET">
          <web:CityName>Strasbourg</web:CityName>
          <web:CountryName>France</web:CountryName>
      </web:GetWeather>
  </soapenv:Body>
</soapenv:Envelope>
'''
def xml = new XmlSlurper().parseText( myInputXML )
// Example 1 //
def GetAllCities = xml.Body.GetWeather.CityName
log.info ("Example 1: "+GetAllCities.text()) // references all 3 CityName nodes, prints out - CairoHeidelbergStrasbourg
// Example 2 //
def Get2ndCity = xml.Body.GetWeather[1].CityName
log.info ("Example 2: "+Get2ndCity.text()) // references 2nd node, prints out - Heidelberg
// Example 3 //
def tmpNode1 = "Body"
def tmpNode2 = "GetWeather[0]" 
   // This problem is with interpolation of GetWeather[0]. tmpNode2 = "GetWeather" would work as Example 1
def tmpNode3 = "CityName"
def GetFirstCity = xml."${tmpNode1}"."${tmpNode2}"."${tmpNode3}"
log.info ("Example 3: "+GetFirstCity.text()) // prints "" - WHY?
log.info ("Interpolation of tmpNodes 1, 2, 3:") 
log.info ("${tmpNode1}") // prints Body
log.info ("${tmpNode2}") // prints GetWeather[0]
log.info ("${tmpNode3}") // prints CityName

P.S。如果我的例子与实际问题无关,我会认为它们有些帮助,但我的目标是改进所提到的stackoverflow答案以支持重复元素。

1 个答案:

答案 0 :(得分:1)

如果您只想修改脚本,请进行以下更改以获得您期望的数据。

更改
// Example 3 //
def tmpNode1 = "Body"
def tmpNode2 = "GetWeather[0]" 
   // This problem is with interpolation of GetWeather[0]. tmpNode2 = "GetWeather" would work as Example 1
def tmpNode3 = "CityName"
def GetFirstCity = xml."${tmpNode1}"."${tmpNode2}"."${tmpNode3}"
log.info ("Example 3: "+GetFirstCity.text()) // prints "" - 

// Example 3 //
def tmpNode1 = "Body"
//removed index from here
def tmpNode2 = "GetWeather" 
def tmpNode3 = "CityName"
//Added index here in below
def GetFirstCity = xml."${tmpNode1}"."${tmpNode2}"[0]."${tmpNode3}"
log.info ("Example 3: "+GetFirstCity.text()) 

优雅方法:

但是,这是我从csv文件生成请求的方式。它不涉及任何xml模板,而是使用StreamingMarkupBuilder构建整个请求xml 。因为这是一种优雅的方式和灵活性。此外,csv非常易读,因为它只包含数据,而不是你提到的任何xpath's

下面的脚本使用了这个非常好的库groovycsv(取决于opencsv),请按照自述文件阅读。

  • 下载jar文件。
  • 将它们复制到SOAPUI_HOME / bin / ext目录下。
  • 重启soapui。

以下是基于csv文件构建请求xml的脚本:

import groovy.xml.*
import static com.xlson.groovycsv.CsvParser.parseCsv
//closure which builds the request based on the data provided
def requestBuilder = { csvData ->
    def builder = new StreamingMarkupBuilder()
    builder.encoding = 'UTF-8'
    def soapRequest = builder.bind {
        mkp.xmlDeclaration()
        namespaces << [soap: 'http://schemas.xmlsoap.org/soap/envelope/',
                           web : 'http://www.webserviceX.NET']
        soap.Envelope {
            soap.Header{}
            soap.Body {
              //loop thru the rows
                csvData.each { row ->
                  //create GetWeather element for each row
                    web.GetWeather{
                        web.CityName(row.CityName)
                        web.CountryName(row.CountryName)
                    }
                }
            }
        }
    }
}
//Used fixed csv data. But you can replace it with reading from file too
def csv = '''CityName,CountryName
Cairo,Africa
Heidelberg,Germany
Strasbourg,France'''
/**
//use this to read from file and remove above statement
def csv = new File('/absolute/csv/file/path').text
**/
//parse the csv using groovy csv library
def data = parseCsv(csv)
//call the above closure get the request and serialize it to string 
def request = XmlUtil.serialize(requestBuilder(data))
log.info request

如果您使用print request而不是log.info,它将显示漂亮的打印xml(您需要在命令行SOAPUI_HOME / bin / soapui.bat中启动soapui) enter image description here