2009-04-08 14 views
66

In Java, come è possibile convertire una stringa che rappresenta un frammento di XML per l'inserimento in un documento XML?Converti frammento XML stringa in nodo documento in Java

ad es.

String newNode = "<node>value</node>"; // Convert this to XML 

quindi inserire questo nodo in un org.w3c.dom.Document come il figlio di un dato nodo?

+0

Vedi anche: http://stackoverflow.com/a/7607435/363573 – Stephan

risposta

52
Element node = DocumentBuilderFactory 
    .newInstance() 
    .newDocumentBuilder() 
    .parse(new ByteArrayInputStream("<node>value</node>".getBytes())) 
    .getDocumentElement(); 
+3

il .parse (nuova StringInputStream (.... dovrebbe leggere .parse (new ByteArrayInputStream (new String ("xml") .getBytes())); – Steen

+5

Odio solo questi commenti e la loro mancanza di markup (o markdown, per quella materia) – Steen

+4

ma questo non copia i bambini... per esempio, se si esegue questa operazione in caso di " bla bla Si ottiene solo senza i suoi figli – grobartn

30

È possibile utilizzare il metodo del documento import (o adopt) per aggiungere frammenti XML:

/** 
    * @param docBuilder 
    *   the parser 
    * @param parent 
    *   node to add fragment to 
    * @param fragment 
    *   a well formed XML fragment 
    */ 
    public static void appendXmlFragment(
     DocumentBuilder docBuilder, Node parent, 
     String fragment) throws IOException, SAXException { 
    Document doc = parent.getOwnerDocument(); 
    Node fragmentNode = docBuilder.parse(
     new InputSource(new StringReader(fragment))) 
     .getDocumentElement(); 
    fragmentNode = doc.importNode(fragmentNode, true); 
    parent.appendChild(fragmentNode); 
    } 
+5

Hmm. Se questa è la soluzione più semplice, devo dire che è piuttosto complicato per un problema così piccolo – Jonik

+0

I ' Lo ha ridotto al minimo - utilizza comunque quello che si ottiene nell'API di JRE, quindi, un po 'di verbosità è inevitabile – McDowell

+3

Questo è esattamente quello che stavo cercando. Non avevo capito che dovevo importare il frammento nella dom prima di aggiungerlo al nodo genitore! –

14

Per quello che vale, ecco una soluzione mi è venuta utilizzando la libreria dom4j . (. Ho fatto controllare che funzioni)

Leggi il frammento XML in un org.dom4j.Document (nota: tutte le classi XML utilizzati qui sotto sono da org.dom4j; vedi Appendice):

String newNode = "<node>value</node>"; // Convert this to XML 
    SAXReader reader = new SAXReader(); 
    Document newNodeDocument = reader.read(new StringReader(newNode)); 

quindi ottenere il documento in cui è inserito il nuovo nodo e l'elemento genitore (essere) da esso. (. Il vostro org.w3c.dom.Document avrebbe bisogno di essere convertito in org.dom4j.Document qui) Per scopi di test, ho creato uno come questo:

Document originalDoc = 
     new SAXReader().read(new StringReader("<root><given></given></root>")); 
    Element givenNode = originalDoc.getRootElement().element("given"); 

Aggiungendo il nuovo elemento figlio è molto semplice:

givenNode.add(newNodeDocument.getRootElement()); 

Fatto. Emissione originalDoc ora cede:

<?xml version="1.0" encoding="utf-8"?> 

<root> 
    <given> 
     <node>value</node> 
    </given> 
</root> 

Appendice: Perché la tua domanda parla org.w3c.dom.Document, ecco come convertire tra questo e org.dom4j.Document.

// dom4j -> w3c 
DOMWriter writer = new DOMWriter(); 
org.w3c.dom.Document w3cDoc = writer.write(dom4jDoc); 

// w3c -> dom4j 
DOMReader reader = new DOMReader(); 
Document dom4jDoc = reader.read(w3cDoc); 

(Se avreste bisogno di entrambi i tipi di Document s regolarmente, potrebbe avere senso di mettere questi in metodi di utilità pulito, magari in una classe chiamata XMLUtils o qualcosa di simile.)

Forse c'è sono modi migliori per farlo, anche senza alcuna libreria di terze parti. Ma dalle soluzioni presentate finora, a mio avviso questo è il modo più semplice, anche se è necessario eseguire le conversioni dom4j < -> w3c.

Aggiornamento (2011): prima di aggiungere la dipendenza di dom4j al codice, notare che it is not an actively maintained project, and has some other problems too. La versione 2.0 migliorata è stata utilizzata per anni, ma è disponibile solo una versione alpha. Potresti prendere in considerazione un'alternativa, come XOM, invece; leggi di più nella domanda collegata sopra.

+0

Se dom4j è un NO-GO, prova questa soluzione: http://stackoverflow.com/a/7607435/363573 – Stephan

6

Ecco un'altra soluzione, utilizzando XOM library, che compete con my dom4j answer. (Questo è parte del mio quest to find a good dom4j replacement dove XOM è stato suggerito come una opzione.)

Prima leggi il frammento XML in un nu.xom.Document:

String newNode = "<node>value</node>"; // Convert this to XML 
Document newNodeDocument = new Builder().build(newNode, ""); 

Quindi, ottenere il documento e il Nodo in base al quale si aggiunge il frammento. Anche in questo caso, a scopo di test creerò il documento da una stringa:

Document originalDoc = new Builder().build("<root><given></given></root>", ""); 
Element givenNode = originalDoc.getRootElement().getFirstChildElement("given"); 

Ora, aggiunge il nodo figlio è semplice, e simile a quello con dom4j (tranne che XOM non consente di aggiungere l'elemento radice originale che appartiene già alla newNodeDocument):

givenNode.appendChild(newNodeDocument.getRootElement().copy()); 

Emissione del documento produce il risultato corretto XML (ed è estremamente semplice con XOM: basta stampare la stringa restituita da originalDoc.toXML()):

<?xml version="1.0"?> 
<root><given><node>value</node></given></root> 

(Se si desidera formattare l'XML correttamente (con indentazioni e linefeed), utilizzare uno Serializer; grazie a Peter Štibraný per averlo indicato.)

Quindi, ammettiamolo, non è molto diverso dalla soluzione dom4j. :) Tuttavia, XOM potrebbe essere un po 'più bello con cui lavorare, perché l'API è meglio documentata e, grazie alla sua filosofia di progettazione, esiste un modo canonico per fare ogni cosa.

Appendice: Anche in questo caso, ecco come convertire tra org.w3c.dom.Document e nu.xom.Document. Utilizzare i metodi di supporto nella classe di XOM DOMConverter:

// w3c -> xom 
Document xomDoc = DOMConverter.convert(w3cDoc); 

// xom -> w3c 
org.w3c.dom.Document w3cDoc = DOMConverter.convert(xomDoc, domImplementation); 
// You can get a DOMImplementation instance e.g. from DOMImplementationRegistry 
+0

Nota che invece di nuovo Builder(). build (new StringReader ("")); puoi anche usare il nuovo Builder(). build ("", "test.xml"); (dove "test.xml" è un URI di base casuale) –

+1

"Se si desidera formattare l'XML correttamente (con indentazioni e linefeed), non sono sicuro di come farlo con XOM." - usando la classe Serializer. Configuralo usando setIndent e setMaxLength e chiama write (document). Il serializzatore –

+0

è anche facile da personalizzare per sottoclassi. –

4

Se stai usando dom4j, basta che si può fare:

documento Document = DocumentHelper.parseText (testo);

(dom4j ora si trova qui: https://github.com/dom4j/dom4j)

+0

Basta andare al loro sito web. Inseriscono annunci Google direttamente nella tipica barra di navigazione generata da Maven! Incredibile! – Thilo

+2

A quanto pare, il sito non è più gestito dai ragazzi di dom4j, ma alcuni grabber di dominio hanno preso il sopravvento ... – Thilo

+0

Una soluzione senza dom4j: http://stackoverflow.com/a/7607435/363573 – Stephan

1

... e se si sta utilizzando puramente XOM, qualcosa di simile:

String xml = "<fakeRoot>" + xml + "</fakeRoot>"; 
    Document doc = new Builder(false).build(xml, null); 
    Nodes children = doc.getRootElement().removeChildren(); 
    for(int ix = 0; ix < children.size(); ix++) { 
     otherDocumentElement.appendChild(children.get(ix)); 
    } 

XOM utilizza fakeroot internamente per fare più o meno lo stesso, quindi dovrebbe essere sicuro, se non proprio elegante.

4
/** 
* 
* Convert a string to a Document Object 
* 
* @param xml The xml to convert 
* @return A document Object 
* @throws IOException 
* @throws SAXException 
* @throws ParserConfigurationException 
*/ 
public static Document string2Document(String xml) throws IOException, SAXException, ParserConfigurationException { 

    if (xml == null) 
    return null; 

    return inputStream2Document(new ByteArrayInputStream(xml.getBytes())); 

} 


/** 
* Convert an inputStream to a Document Object 
* @param inputStream The inputstream to convert 
* @return a Document Object 
* @throws IOException 
* @throws SAXException 
* @throws ParserConfigurationException 
*/ 
public static Document inputStream2Document(InputStream inputStream) throws IOException, SAXException, ParserConfigurationException { 
    DocumentBuilderFactory newInstance = DocumentBuilderFactory.newInstance(); 
    newInstance.setNamespaceAware(true); 
    Document parse = newInstance.newDocumentBuilder().parse(inputStream); 
    return parse; 
} 
1

Prova jcabi-xml, con un uno di linea:

Node node = new XMLDocument("<node>value</node>").node();