groovyを使用してXMLで検索+置換するにはどうすればよいですか?
このコードをテスターのSoapUIスクリプト用に提供するので、できるだけ短くて簡単なものが必要です。
より具体的には、どのように向きを変えるのですか?
<root><data></data></root>
の中へ:
<root><data>value</data></root>
XSLT で実行できることのいくつかは、何らかの形式の「検索と置換」でも実行できます。それはすべて、問題の複雑さと、ソリューションをどの程度「一般的」に実装したいかによって異なります。独自の例をもう少し一般的にするには、次のようにします。
xml.replaceFirst("<Mobiltlf>[^<]*</Mobiltlf>", '<Mobiltlf>32165487</Mobiltlf>')
選択するソリューションはあなた次第です。私自身の経験では (非常に単純な問題の場合)、単純な文字列ルックアップを使用する方が、本格的な XSLT 変換を使用するよりも高速な正規表現を使用するよりも高速です (実際には理にかなっています)。
私はDOMCategoryでいくつかのテストを行いましたが、ほとんど機能しています。置換を実行することはできますが、infopathに関連するコメントの一部が消えます。私は次のような方法を使用しています:
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-行だけです。そのアイデアを持っている人はいますか?
これがこれまでのところ最良の答えであり、正しい結果が得られるので、私は答えを受け入れるつもりです:)しかし、それは私には少し大きすぎます。私は代替案が次のとおりであることを説明したほうがいいと思います:
xml.replace("<Mobiltlf></Mobiltlf>", <Mobiltlf>32165487</Mobiltlf>")
しかし、それはあまりxml'yではないので、私は別の方法を探すと思いました。また、最初のタグが常に空であるかどうかはわかりません。
属性を保持するには、小さなプログラムを次のように変更するだけです (テスト用のサンプル ソースを含めました)。
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", "bob@email.com" )
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">bob@email.com</E-mail-adresse>
</application:FA_Ansoegning>
一致する正規表現には、(1) 開始タグ (属性を含む)、(2) タグの「古い」コンテンツ、(3) 終了タグの 3 つのキャプチャ グループが含まれていることに注意してください。置換文字列は、$i 構文 (バックスラッシュを使用して GString でエスケープする) を介して、これらのキャプチャされたグループを参照します。ヒント: 正規表現は非常に強力な動物です。正規表現に慣れることは非常に価値があります ;-) .
いくつかの熱狂的なコーディングの後、私は光を見て、このようにしました
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 ドキュメントからのコメントやメタデータなどを保持しないため、別の方法を見つける必要があります
素晴らしい!助けてくれてありがとう:)
それは私の問題をはるかにクリーンで簡単な方法で解決します。最終的には次のようになります。
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", "bob@email.com" )
println input
これをテストツールSoapUIで使用するためにテスターに提供しているので、コピーと貼り付けを簡単にするために、これを「ラップ」しようとしました。
これは私の目的には十分ですが、もう1つ「ツイスト」を追加できれば完璧です。
入力にこれが含まれているとしましょう...
<Mobiltlf type="national" anotherattribute="value"></Mobiltlf>
...そして、値を置き換えても、2つの属性を保持したかったのです。そのためにも正規表現を使用する方法はありますか?
XML を更新する 3 つの "公式" groovy 方法については、ページhttp://groovy.codehaus.org/Processing+XMLの「XML の更新」セクションで説明されています。
その3つのうち、DOMCategoryの方法だけがXMLコメントなどを保持しているようです.
私には、実際のコピーと検索と置換は、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', 'john.doe@foobar.com')
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>john.doe@foobar.com</E-mail-adresse>
</application:FA_Ansoegning>