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

在Groovy中将一个节点从一个XML树复制到另一个XML树,xml,groovy,soapui,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:Bod

在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>
         <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>

苹果
3.
香蕉
0
问题:我如何才能做到这一点


我当前的解决方案出现错误,因为
req[“//ns1:mylist[1]”]
为空。我已经尝试了许多不同的方法,但没有一种有效。

这里有一个只替换XML的有效解决方案(省略了文件处理)

@Grab('xmlunit:xmlunit:1.5')
导入groovy.xml.XmlUtil
导入org.custommonkey.xmlunit.xmlunit
def xml=''
苹果
3.
香蕉
0
'''
def tmpl=''
'''
def结果=“”
苹果
3.
香蕉
0
'''
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)
来源[soapNS.Body][orgNS.list][0]。每个{
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(真)
setNormalizeWhitespace(true)
断言XMLUnit.compareXML(XmlUtil.serialize(目标),XmlUtil.serialize(结果))
如果有任何问题,请随时提问


另外,您的帖子中的预期结果不是有效的XML文件。

我认为问题在于
[]
标记法,它在
req
对象中工作不正常(我不知道为什么):
req[“//ns1:mylist[1]”]
以及
req.namespace[“ns1]”http://examle.com“

不要使用
[XPath]
而是尝试使用
getDomNode(XPath)
显式调用函数,因为
namespaces[“ns1]”=http://example.com“
这似乎也不像我之前说的那样有效(奇怪的是,
req
对象不工作,而
源代码
对象工作正常)

最后,使用xmlbeans,您不能直接从另一个文档中添加节点,首先必须导入该节点,因此最后您的代码如下所示(我尝试过并使用SOAPUI 5.0.0):


希望这有帮助,

非常感谢@albciff

我最终实现的解决方案如下所示:

def groovyUtils=new com.eviware.soapui.support.groovyUtils(上下文)
defXML
def req=groovyUtils.getXmlHolder(“发送数据请求”)
请求名称空间[“ns1”]=”http://examle.com"
def parent=holder.getDomNode(“//ns1:myList[1]”)
def doc=parent.getOwnerDocument()
def folder=新文件('res')
if(folder.exists())
{
文件夹。eachDir()
{f->
def xmlfile=新文件(f.absolutePath+“/data.xml”)
if(xmlfile.exists())
{
def source=new com.eviware.soapui.support.XmlHolder(xmlfile.text)
source.namespace[“ns2”]=”http://example.org"
//我可以在这里修改如下内容:
source[“//ns2:list/item[1]/quant”]=“5”
使用(groovy.xml.dom.domcegory)
{
for(source.getDomNodes(“//ns2:list/ns2:item”)中的项)
{
def importNode=doc.importNode(项目,true)
parent.appendChild(importNode)
}
}
}
}
}
请求updateProperty()

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

example.com
example.org
名称空间在目的上不同?是的,脚本应该是名称空间感知的。您似乎在用
?Thx@rubesmoker关闭
,我在编写最小示例时犯了一个错误。非常感谢!这让我感到内疚o正确的方向:获取DOM节点并使用其“所有者文档”。我实现它的方式是:接收列表的DOM注释,使用它调用Soap请求的所有者文档上的importNode,在那里接收DOM节点并将其附加到所需的位置。
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>
@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))
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)
                    // CODE ADDED
                    def node = req.getDomNode("//*:mylist[1]");
                    def copyItem = node.getOwnerDocument().importNode(item,true);
                    node.appendChild(copyItem);
                }
            }
        }
    }
}

req.updateProperty()