将节点从一个XML树复制到Groovy中的另一个XML树

时间:2014-08-11 15:08:07

标签: xml groovy soapui

在SoapUI中,我想使用Groovy脚本从目录中挑选xml文件,在其中查找特定的节点树并插入到测试请求中。

让我们考虑目录res/001/data.xml中包含内容

的以下文件
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.org">
   <soapenv:Header/>
   <soapenv:Body>
      <ns:list>
         <ns:item attr1="yes">
             <title>Apple</title>
             <quant>3</quant>
         </ns:item>
         <ns:item attr1="no">
             <title>Banana</title>
             <quant>0</quant>
         </ns:item>
      </ns:list>
   </soapenv:Body>
</soapenv:Envelope>

肥皂请求模板:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.com">
   <soapenv:Header/>
   <soapenv:Body>
      <ns:mylist/>
   </soapenv:Body>
</soapenv:Envelope>

我尝试使用脚本中的XmlHolder将列表读入我的请求中:

def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def xml
def req = groovyUtils.getXmlHolder( "SendData#Request" )
req.namespaces["ns1"] = "http://examle.com"

def folder = new File('res')

if (folder.exists())
{
    folder.eachDir( ) 
    { f ->
        def xmlfile = new File( f.absolutePath + "/data.xml")
        if( xmlfile.exists() )
        {
            def source = new com.eviware.soapui.support.XmlHolder( xmlfile.text )
            source.namespaces["ns2"] = "http://example.org"
            use (groovy.xml.dom.DOMCategory)
            {
                for( item in source.getDomNodes( "//ns2:list/ns2:item" )) 
                {
                    log.info item.xml
                    req["//ns1:mylist[1]"].appendChild(item.xml)
                }
            }
        }
    }
}

req.updateProperty()

我的预期结果是:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.com">
   <soapenv:Header/>
   <soapenv:Body>
      <ns:mylist>
         <ns:item attr1="yes">
             <title>Apple</title>
             <quant>3</quant>
         </ns:item>
         <ns:item attr1="no">
             <title>Banana</title>
             <quant>0</quant>
         </ns:item>
      </ns:mylist>
   </soapenv:Body>
</soapenv:Envelope>

问题:如何实现这一目标?

我当前的解决方案会出错,因为req["//ns1:mylist[1]"]为空。我已经尝试了很多不同的方法,现在它们都没有用。

3 个答案:

答案 0 :(得分:1)

我认为问题是[]符号在req对象中无法正常工作(我无法弄清楚原因):req["//ns1:mylist[1]"]还有{{1 }}

而不是使用req.namespaces["ns1"] = "http://examle.com"尝试使用[XPath]显式调用该函数而使用通配符代替名称而不是前缀,因为getDomNode(XPath)似乎也不像我之前所说的那样工作( namespaces["ns1"] = "http://example.com"对象很奇怪,req对象无法正常工作,但这很奇怪。

最后使用xmlbeans,你无法直接从另一个文档添加一个节点,首先你必须导入节点,所以最后你的代码看起来像(我试过并使用SOAPUI 5.0.0):

source

希望这有帮助,

答案 1 :(得分:0)

这里您有一个仅用于替换XML的工作解决方案(省略了文件处理)。

@Grab('xmlunit:xmlunit:1.5')

import groovy.xml.XmlUtil
import org.custommonkey.xmlunit.XMLUnit

def xml = '''
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.org">
   <soapenv:Header/>
   <soapenv:Body>
      <ns:list>
         <ns:item attr1="yes">
             <title>Apple</title>
             <quant>3</quant>
         </ns:item>
         <ns:item attr1="no">
             <title>Banana</title>
             <quant>0</quant>
         </ns:item>
      </ns:list>
   </soapenv:Body>
</soapenv:Envelope>
'''

def tmpl = '''
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.com">
   <soapenv:Header/>
   <soapenv:Body>
      <ns:mylist/>
   </soapenv:Body>
</soapenv:Envelope>
'''

def result = '''
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.com">
   <soapenv:Header/>
   <soapenv:Body>
      <ns:mylist>
         <ns:item attr1="yes">
             <title>Apple</title>
             <quant>3</quant>
         </ns:item>
         <ns:item attr1="no">
             <title>Banana</title>
             <quant>0</quant>
         </ns:item>
      </ns:mylist>
   </soapenv:Body>
</soapenv:Envelope>
'''

def soapNS = new groovy.xml.Namespace("http://schemas.xmlsoap.org/soap/envelope/", 'soapenv')
def orgNS = new groovy.xml.Namespace("http://example.org", 'ns')
def comNS = new groovy.xml.Namespace("http://example.com", 'ns')
def source = new XmlParser().parseText(xml)
def target = new XmlParser().parseText(tmpl)

source[soapNS.Body][orgNS.list][0].each {
    def item = target[soapNS.Body][comNS.mylist][0].appendNode('ns:item', [attr1:it.@attr1])
    item.appendNode('title', it.title.text())
    item.appendNode('quant', it.quant.text())    
}

XMLUnit.setIgnoreWhitespace(true)
XMLUnit.setIgnoreComments(true)
XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true)
XMLUnit.setNormalizeWhitespace(true)
assert XMLUnit.compareXML(XmlUtil.serialize(target), XmlUtil.serialize(result))

如有任何问题,请随时提出。

P.S。您帖子中的预期结果不是有效的XML文件。

答案 2 :(得分:0)

非常感谢@albciff!

我最终实施的解决方案是这样的:

def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def xml
def req = groovyUtils.getXmlHolder( "SendData#Request" )
req.namespaces["ns1"] = "http://examle.com"
def parent = holder.getDomNode( "//ns1:myList[1]" )
def doc = parent.getOwnerDocument()

def folder = new File('res')

if (folder.exists())
{
    folder.eachDir( ) 
    { f ->
        def xmlfile = new File( f.absolutePath + "/data.xml")
        if( xmlfile.exists() )
        {
            def source = new com.eviware.soapui.support.XmlHolder( xmlfile.text )
            source.namespaces["ns2"] = "http://example.org"

            // I can modify things here like that:
            source["//ns2:list/item[1]/quant"] = "5"

            use (groovy.xml.dom.DOMCategory)
            {
                for( item in source.getDomNodes( "//ns2:list/ns2:item" )) 
                {
                    def importNode = doc.importNode(item , true)
                    parent.appendChild( importNode )
                }
            }
        }
    }
}

req.updateProperty()

请节点:此最小示例未经过测试。