2009-04-08 22 views
66

En Java, ¿cómo se puede convertir una cadena que representa un fragmento de XML para su inserción en un documento XML?Convertir fragmento String XML en Document Node en Java

p. Ej.

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

Luego inserte este nodo en una org.w3c.dom.Document como el hijo de un nodo dado?

+0

Ver también: http://stackoverflow.com/a/7607435/363573 – Stephan

Respuesta

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

la .parse (nuevo StringInputStream (.... debería leer .parse (new ByteArrayInputStream (new String ("xml") .getBytes())); – Steen

+5

Odio estas cajas de comentarios y su falta de marcado (o de descuento, para el caso) – Steen

+4

pero esto no copia los niños... por ejemplo, si usted hace esto en el caso de " bla bla Sólo se pone sin sus hijos – grobartn

30

Puede utilizar el método del documento import (o adopt) para añadir fragmentos 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. Si esta es la solución más simple, debo decir que es bastante complicado para un problema tan pequeño. – Jonik

+0

I ' lo redujo al mínimo, aún así usa lo que obtienes en la API de JRE, por lo tanto, un poco de verbosidad es inevitable. – McDowell

+3

Eso es exactamente lo que estaba buscando. ¡No me di cuenta de que tenía que importar el fragmento al dominio antes de anexarlo al nodo padre! –

14

Por lo que vale la pena, he aquí una solución que se me ocurrió usar la biblioteca dom4j . (. Yo comprobar que funciona)

Leer el fragmento de XML en un org.dom4j.Document (nota: todas las clases XML utilizados a continuación son de org.dom4j; véase el Apéndice):

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

a continuación, obtener el Documento en el cual se inserta el nuevo nodo, y el Elemento padre (a ser) a partir de él. (. Necesitaría Su org.w3c.dom.Document que ser convertido a org.dom4j.Document aquí) Para propósitos de prueba, he creado uno como este:

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

Añadiendo el nuevo elemento secundario es muy simple:

givenNode.add(newNodeDocument.getRootElement()); 

Hecho. La salida de originalDoc ahora rinde:

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

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

Apéndice: Debido a su pregunta habla de org.w3c.dom.Document, aquí está cómo convertir entre eso y 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); 

(Si lo que se necesita ambos tipos de Document s regularmente, podría tener sentido para poner estos en métodos de utilidad aseado, tal vez en una clase llamada XMLUtils o algo por el estilo.)

Tal vez hay hay mejores formas de hacerlo, incluso sin bibliotecas de terceros. Pero de las soluciones presentadas hasta ahora, en mi opinión, esta es la manera más fácil, incluso si necesita hacer las conversiones dom4j < -> w3c.

Actualización (2011): antes de agregar dependencia dom4j a su código, tenga en cuenta que it is not an actively maintained project, and has some other problems too. La versión mejorada 2.0 ha estado en proceso durante siglos, pero solo hay una versión alfa disponible. Es posible que desee considerar una alternativa, como XOM, en su lugar; Lea más en la pregunta vinculada arriba.

+0

Si dom4j es un NO-GO, intente con esta solución: http://stackoverflow.com/a/7607435/363573 – Stephan

6

Aquí hay otra solución, usando el XOM library, que compite con my dom4j answer. (Esto es parte de mi quest to find a good dom4j replacement donde se sugirió XOM como una opción.)

Primero leyó el fragmento de XML en un nu.xom.Document:

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

A continuación, obtener el documento y el Nodo bajo las cuales se añade el fragmento. Una vez más, para fines de prueba Voy a crear el documento de una cadena:

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

Ahora, añadiendo que el nodo hijo es simple, y similar a la dom4j (XOM excepto que no permite que se agrega el elemento raíz original que ya pertenece a newNodeDocument):

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

Salida del documento XML produce el resultado correcto (y es muy fácil con XOM: acaba de imprimir la cadena devuelta por originalDoc.toXML()):

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

(Si desea formatear el XML muy bien (con sangrías y avances de línea), use un Serializer; gracias a Peter Štibraný por señalar esto.)

Por lo tanto, es cierto que esto no es muy diferente de la solución dom4j. :) Sin embargo, XOM puede ser un poco mejor para trabajar, ya que la API está mejor documentada, y debido a su filosofía de diseño, hay una manera canónica para hacer cada cosa.

Apéndice: Una vez más, aquí es cómo convertir entre org.w3c.dom.Document y nu.xom.Document. Utilizar los métodos de ayuda en la clase de 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

Tenga en cuenta que en su lugar de nuevo Builder(). build (nuevo StringReader ("")); también puede usar el nuevo Builder(). build ("", "test.xml"); (donde "test.xml" es un URI base aleatorio) –

+1

"Si quería formatear el XML muy bien (con sangrías y avances de línea), no estoy seguro de cómo hacer eso con XOM". - usando la clase Serializer. Configúrelo usando setIndent y setMaxLength, y llame a write (document). –

+0

Serializador también es fácil de personalizar mediante subclases. –

4

Si está utilizando dom4j, sólo se puede hacer:

documento Documento = DocumentHelper.parseText (texto);

(dom4j ahora se encuentra aquí: https://github.com/dom4j/dom4j)

+0

Acabo de ir a su sitio web. ¡Colocan los anuncios de Google en la barra de navegación generada por Maven! ¡Increíble! – Thilo

+2

Aparentemente, el sitio ya no es operado por los chicos de dom4j, pero algunos capturadores de dominio tomaron el control ... – Thilo

+0

Una solución dom4j-less: http://stackoverflow.com/a/7607435/363573 – Stephan

1

... y si usted está usando puramente XOM, algo como esto:

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 utiliza Fakeroot internamente para hacer más o menos lo mismo, por lo que debería ser seguro, si no exactamente 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

Trate jcabi-xml, con un un trazador de líneas:

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