如何使用groovy在XML中進行搜索+替換?如何使用groovy在XML中進行搜索+替換?
我需要儘可能簡短/簡單的東西,因爲我將這些代碼交給測試人員進行SoapUI腳本編寫。
更具體地說,我怎麼轉:
<root><data></data></root>
到:
<root><data>value</data></root>
如何使用groovy在XML中進行搜索+替換?如何使用groovy在XML中進行搜索+替換?
我需要儘可能簡短/簡單的東西,因爲我將這些代碼交給測試人員進行SoapUI腳本編寫。
更具體地說,我怎麼轉:
<root><data></data></root>
到:
<root><data>value</data></root>
你可以用XSLT做的一些事情你也可以通過某種形式的'搜索&替換'來完成。這完全取決於問題的複雜程度以及您希望實施解決方案的「通用性」。爲使您自己的示例稍微更通用:
xml.replaceFirst("<Mobiltlf>[^<]*</Mobiltlf>", '<Mobiltlf>32165487</Mobiltlf>')
您選擇的解決方案由您決定。根據我自己的經驗(對於非常簡單的問題),使用簡單的字符串查找比使用正則表達式要快得多,這比使用完整的XSLT轉換(實際上有意義)要快。
一些瘋狂的編碼後,我看到了光,做了這樣的
import org.custommonkey.xmlunit.Diff
import org.custommonkey.xmlunit.XMLUnit
def input = '''<root><data></data></root>'''
def expectedResult = '''<root><data>value</data></root>'''
def xml = new XmlParser().parseText(input)
def p = xml.'**'.data
p.each{it.value="value"}
def writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(xml)
def result = writer.toString()
XMLUnit.setIgnoreWhitespace(true)
def xmlDiff = new Diff(result, expectedResult)
assert xmlDiff.identical()
不幸的是這將不保留意見和元數據等,從原始的XML文檔,所以我將不得不另謀出路
三「官方」常規更新XML的方式http://groovy.codehaus.org/Processing+XML頁描述,「更新XML」部分。
三個似乎只有DOMCategory方式保留XML註釋等
我DOMCategory做了一些一些測試和它幾乎工作。我可以讓替換髮生,但一些與信息相關的評論消失。在這樣一個源
def rtv = { xml, tag, value ->
def doc = DOMBuilder.parse(new StringReader(xml))
def root = doc.documentElement
use(DOMCategory) { root.'**'."$tag".each{it.value=value} }
return DOMUtil.serialize(root)
}
:我使用的方法是這樣
<?xml version="1.0" encoding="utf-8"?>
<?mso-infoPathSolution name="urn:schemas-microsoft-com:office:infopath:FA_Ansoegning:http---ementor-dk-application-2007-06-22-" href="manifest.xsf" solutionVersion="1.0.0.14" productVersion="12.0.0" PIVersion="1.0.0.0" ?>
<?mso-application progid="InfoPath.Document" versionProgid="InfoPath.Document.2"?>
<application:FA_Ansoegning xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:application="http://corp.dk/application/2007/06/22/"
xmlns:xd="http://schemas.microsoft.com/office/infopath/2003"
xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/200 8-04-14T14:31:48">
<Mobiltlf></Mobiltlf>
<E-mail-adresse></E-mail-adresse>
</application:FA_Ansoegning>
從結果中唯一缺少的是< mso-從結果行?任何人有這樣的想法?
對我來說,實際的副本&搜索&替換看起來像XSLT樣式表的完美工作。在XSLT中,只需複製所有內容(包括有問題的項目)就可以了,只需將數據插入需要的地方即可。您可以通過XSL參數傳遞數據的特定值,也可以動態修改樣式表本身(如果您在Groovy程序中包含字符串)。調用這個XSLT來轉換Groovy中的文檔非常簡單。
我趕緊鵝卵石以下Groovy腳本在一起(但我毫不懷疑它甚至可以更簡單/緊湊寫入):
import javax.xml.transform.TransformerFactory
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.stream.StreamSource
def xml = """
<?xml version="1.0" encoding="utf-8"?>
<?mso-infoPathSolution name="urn:schemas-microsoft-com:office:infopath:FA_Ansoegning:http---ementor-dk-application-2007-06-22-" href="manifest.xsf" solutionVersion="1.0.0.14" productVersion="12.0.0" PIVersion="1.0.0.0" ?>
<?mso-application progid="InfoPath.Document" versionProgid="InfoPath.Document.2"?>
<application:FA_Ansoegning xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:application="http://ementor.dk/application/2007/06/22/"
xmlns:xd="http://schemas.microsoft.com/office/infopath/2003"
xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/200 8-04-14T14:31:48">
<Mobiltlf></Mobiltlf>
<E-mail-adresse></E-mail-adresse>
</application:FA_Ansoegning>
""".trim()
def xslt = """
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="mobil" select="'***dummy***'"/>
<xsl:param name="email" select="'***dummy***'"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Mobiltlf">
<xsl:copy>
<xsl:value-of select="\$mobil"/>
</xsl:copy>
</xsl:template>
<xsl:template match="E-mail-adresse">
<xsl:copy>
<xsl:value-of select="\$email"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
""".trim()
def factory = TransformerFactory.newInstance()
def transformer = factory.newTransformer(new StreamSource(new StringReader(xslt)))
transformer.setParameter('mobil', '1234567890')
transformer.setParameter('email', '[email protected]')
transformer.transform(new StreamSource(new StringReader(xml)), new StreamResult(System.out))
運行此腳本生成:
<?xml version="1.0" encoding="UTF-8"?><?mso-infoPathSolution name="urn:schemas-microsoft-com:office:infopath:FA_Ansoegning:http---ementor-dk-application-2007-06-22-" href="manifest.xsf" solutionVersion="1.0.0.14" productVersion="12.0.0" PIVersion="1.0.0.0" ?>
<?mso-application progid="InfoPath.Document" versionProgid="InfoPath.Document.2"?>
<application:FA_Ansoegning xmlns:application="http://ementor.dk/application/2007/06/22/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xd="http://schemas.microsoft.com/office/infopath/2003" xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/200 8-04-14T14:31:48">
<Mobiltlf>1234567890</Mobiltlf>
<E-mail-adresse>[email protected]</E-mail-adresse>
</application:FA_Ansoegning>
這就是迄今爲止最好的答案,它給出了正確的結果,所以我會接受答案:) 但是,這對我來說有點過大。我想我最好解釋,替代是:
xml.replace("<Mobiltlf></Mobiltlf>", <Mobiltlf>32165487</Mobiltlf>")
但這不是很xml'y所以我想我會尋找替代品。另外,我無法確定第一個標籤是否一直是空的。
太棒了!非常感謝您的幫助:)
這樣就以更簡潔更簡單的方式解決了我的問題。它結束了看起來像這樣:
def rtv = { xmlSource, tagName, newValue ->
regex = "<$tagName>[^<]*</$tagName>"
replacement = "<$tagName>${newValue}</$tagName>"
xmlSource = xmlSource.replaceAll(regex, replacement)
return xmlSource
}
input = rtv(input, "Mobiltlf", "32165487")
input = rtv(input, "E-mail-adresse", "[email protected]")
println input
因爲我給這對我們的測試人員在他們的測試工具了SoapUI使用,我已經試過「包裝」它,使他們更容易複製和糊。
這是對我來說已經足夠了,但它是完美的,如果我們可以添加更多的「扭曲」
比方說在它的輸入有這個...
<Mobiltlf type="national" anotherattribute="value"></Mobiltlf>
..我們希望保留這兩個屬性,即使我們取代了這個值。有沒有辦法使用regexp呢?
要保留的屬性只需要修改你的小程序是這樣的(我已經包含了樣本源進行測試):
def input = """
<?xml version="1.0" encoding="utf-8"?>
<?mso-infoPathSolution name="urn:schemas-microsoft-com:office:infopath:FA_Ansoegning:http---ementor-dk-application-2007-06-22-" href="manifest.xsf" solutionVersion="1.0.0.14" productVersion="12.0.0" PIVersion="1.0.0.0" ?>
<?mso-application progid="InfoPath.Document" versionProgid="InfoPath.Document.2"?>
<application:FA_Ansoegning xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:application="http://ementor.dk/application/2007/06/22/"
xmlns:xd="http://schemas.microsoft.com/office/infopath/2003"
xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/200 8-04-14T14:31:48">
<Mobiltlf type="national" anotherattribute="value"></Mobiltlf>
<E-mail-adresse attr="whatever"></E-mail-adresse>
</application:FA_Ansoegning>
""".trim()
def rtv = { xmlSource, tagName, newValue ->
regex = "(<$tagName[^>]*>)([^<]*)(</$tagName>)"
replacement = "\$1${newValue}\$3"
xmlSource = xmlSource.replaceAll(regex, replacement)
return xmlSource
}
input = rtv(input, "Mobiltlf", "32165487")
input = rtv(input, "E-mail-adresse", "[email protected]")
println input
運行此腳本生成:
<?xml version="1.0" encoding="utf-8"?>
<?mso-infoPathSolution name="urn:schemas-microsoft-com:office:infopath:FA_Ansoegning:http---ementor-dk-application-2007-06-22-" href="manifest.xsf" solutionVersion="1.0.0.14" productVersion="12.0.0" PIVersion="1.0.0.0" ?>
<?mso-application progid="InfoPath.Document" versionProgid="InfoPath.Document.2"?>
<application:FA_Ansoegning xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:application="http://ementor.dk/application/2007/06/22/"
xmlns:xd="http://schemas.microsoft.com/office/infopath/2003"
xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/200 8-04-14T14:31:48">
<Mobiltlf type="national" anotherattribute="value">32165487</Mobiltlf>
<E-mail-adresse attr="whatever">[email protected]</E-mail-adresse>
</application:FA_Ansoegning>
注意,匹配正則表達式現在包含3個捕獲組:(1)開始標記(包括屬性),(2)無論您的標記的「舊」內容和(3)結束標記。替換字符串通過$ i語法引用這些捕獲的組(使用反斜槓在GString中轉義它們)。只是一個提示:正則表達式是非常強大的動物,熟悉它們真的很值得;-)。
恐怕這有點冗長了,它只涉及閱讀,據我所知。我需要搜索特定標記並插入/替換它的值 – 2008-09-18 12:18:38