Domanda

Come faccio a usare groovy di ricerca+sostituire in XML?

Ho bisogno di qualcosa di più breve e semplice possibile, in quanto sarò dare questo codice per i tester per il loro SoapUI di scripting.

Più specificamente, come faccio a girare:

<root><data></data></root>

in:

<root><data>value</data></root>
È stato utile?

Soluzione

Alcune delle cose che si possono fare con un XSLT si può anche fare con una qualche forma di "search & replace".Dipende da quanto è complesso il problema è come e 'generico' che si desidera implementare la soluzione.Per rendere il tuo esempio leggermente più generico:

xml.replaceFirst("<Mobiltlf>[^<]*</Mobiltlf>", '<Mobiltlf>32165487</Mobiltlf>')

La soluzione scelta è fino a voi.Nella mia esperienza (molto semplici problemi utilizzando la semplice stringa di ricerche è più veloce rispetto all'utilizzo di espressioni regolari, che è ancora più veloce rispetto all'utilizzo di una completa trasformazione XSLT (senso in realtà).

Altri suggerimenti

Dopo alcuni frenetica di codifica ho visto la luce e fatto come questo

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()

Purtroppo questo non conservare i commenti e i metadati ecc, dal documento xml originale, quindi dovrò trovare un altro modo

Ho fatto alcuni test con DOMCategory e di lavoro.Posso fare la sostituzione avvenga, ma alcuni di infopath relativi commenti scompaiono.Io sto usando un metodo simile a questo:

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)    
}

su una fonte di simile a questo:

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

L'unica cosa che mancava il risultato e ' il <?mso- lines from the result.Chiunque abbia un idea di che?

Che è la risposta migliore finora e si dà il giusto risultato, così ho intenzione di accettare la risposta :) Tuttavia, è un po ' troppo grande per me.Penso che farei meglio a spiegare che l'alternativa è:

xml.replace("<Mobiltlf></Mobiltlf>", <Mobiltlf>32165487</Mobiltlf>")

Ma non è molto xml y così ho pensato di cercare un'alternativa.Inoltre, non posso essere sicuro che il primo tag è vuoto per tutto il tempo.

Per mantenere gli attributi basta modificare il tuo piccolo programma come questo (ho incluso un esempio di fonte di prova):

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

L'esecuzione di questo script produce:

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

Nota che corrispondono all'espressione regolare ora contiene 3 gruppi di cattura:(1) il tag di inizio (inclusi gli attributi), (2), qualsiasi sia il 'vecchio' contenuto del tag e (3) il tag di chiusura.La stringa di sostituzione si riferisce a questi gruppi catturati attraverso il $i di sintassi (con le barre rovesciate, per poi fuggire in GString).Solo un consiglio:le espressioni regolari sono uno strumento molto potente animali, è davvero ottima per acquisire familiarità con loro ;-) .

Tre "ufficiale" groovy percorsi di aggiornamento XML sono descritte in questa pagina http://groovy.codehaus.org/Processing+XML, la sezione "Aggiornamento XML".

Dei tre sembra solo DOMCategory modo conserva i commenti XML etc.

A me la copia reale & cerca & sostituisci sembra che il lavoro perfetto per un foglio di stile XSLT.In un XSLT è avere alcun problema a tutti di copiare tutto (compresi gli elementi che si stanno avendo problemi con l') e semplicemente inserisci i tuoi dati dove è richiesto.È possibile passare il valore specifico dei dati tramite un parametro XSL o è possibile modificare dinamicamente il foglio di stile (se si includono come una stringa di Groovy programma).Chiamando questo XSLT per trasformare il documento(s) da Groovy è molto semplice.

Ho subito acciottolate il seguente script Groovy insieme (ma non ho dubbi che può essere scritto anche più semplice/compact):

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

L'esecuzione di questo script produce:

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

Geniale!La ringrazio molto per l'aiuto :)

Che risolve il mio problema in modo molto più pulito e più facile.È finito così:

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

Dal momento che sto dando questo per i nostri tester per l'uso nel loro strumento di test SoapUI, ho cercato di "avvolgere", per rendere più facile per loro di copia e incolla.

Questo è abbastanza buono per il mio scopo, ma sarebbe perfetto se si potesse aggiungere un "twist"

Diciamo che l'ingresso era questo...

<Mobiltlf type="national" anotherattribute="value"></Mobiltlf>

...e abbiamo voluto mantenere quei due attributi, anche se abbiamo sostituito il valore.C'è un modo per usare le regexp per questo?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top