web-dev-qa-db-fra.com

Convertir un fragment XML de chaîne en document Node in Java

Dans Java Comment pouvez-vous convertir une chaîne qui représente un fragment de XML à insérer dans un document XML?

par exemple.

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

Ensuite, insérez ce noeud dans un org.w3c.dom.Document en tant qu'enfant d'un noeud donné?

71
James Wardle
Element node =  DocumentBuilderFactory
    .newInstance()
    .newDocumentBuilder()
    .parse(new ByteArrayInputStream("<node>value</node>".getBytes()))
    .getDocumentElement();
60
izb

Vous pouvez utiliser le document import (ou adopter) pour ajouter des fragments 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);
  }
32
McDowell

Pour ce que cela vaut, voici une solution que j'ai proposée avec la bibliothèque dom4j . (J'ai vérifié que ça marche.)

Lire le fragment XML dans un org.dom4j.Document (note: toutes les classes XML utilisées ci-dessous proviennent de org.dom4j; voir l’Annexe):

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

Ensuite, récupérez le document dans lequel le nouveau nœud est inséré, ainsi que l'élément parent (à être). (Votre document org.w3c.dom.Document doit être converti en fichier org.dom4j.Document ici.) À des fins de test, j'en ai créé un comme ceci:

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

Ajouter le nouvel élément enfant est très simple:

    givenNode.add(newNodeDocument.getRootElement());

Terminé. Produire originalDoc donne maintenant:

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

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

Annexe : Parce que votre question parle de org.w3c.dom.Document, voici comment convertir entre cela et 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 vous avez besoin des deux types de Documents régulièrement, il peut être judicieux de les mettre dans des méthodes utilitaires ordonnées, peut-être dans une classe appelée XMLUtils ou quelque chose du genre.)

Peut-être y a-t-il de meilleurs moyens de le faire, même sans bibliothèques tierces. Mais parmi les solutions présentées jusqu’à présent, c’est à mon avis la solution la plus simple, même si vous devez effectuer les conversions dom4j <-> w3c.

Mise à jour (2011): avant d'ajouter la dépendance dom4j à votre code, notez que c'est pas an activement maintenu le projet, et a quelques autres problèmes aussi . La version 2.0 améliorée est à l'œuvre depuis longtemps, mais seule une version alpha est disponible. Vous voudrez peut-être envisager une alternative, telle que XOM, à la place; lisez plus dans la question liée ci-dessus.

14
Jonik
/**
*
* 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;
}
6
Giordano Maestro

Voici encore une autre solution, en utilisant la bibliothèque [~ # ~] xom [~ # ~] , en concurrence avec - ma réponse dom4j . (Cela fait partie de ma quête pour trouver un bon remplacement pour dom4j où XOM a été suggéré comme une option.)

Commencez par lire le fragment XML dans un nu.xom.Document:

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

Ensuite, récupérez le document et le Node sous lequel le fragment est ajouté. Encore une fois, à des fins de test, je vais créer le document à partir d'une chaîne:

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

Maintenant, ajouter le nœud enfant est simple et semblable à celui de dom4j (sauf que XOM ne vous permet pas d'ajouter l'élément racine d'origine qui appartient déjà à newNodeDocument):

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

La sortie du document donne le résultat XML correct (et est extrêmement facile avec XOM: il suffit d’imprimer la chaîne renvoyée par originalDoc.toXML()):

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

(Si vous souhaitez bien formater le XML (avec des indentations et des sauts de ligne), utilisez un Serializer ; merci à Peter Štibraný pour l'avoir signalé.)

Donc, il est vrai que ce n’est pas très différent de la solution dom4j. :) Cependant, il est peut-être plus agréable de travailler avec XOM, car l’API est mieux documentée et, en raison de sa philosophie de conception, il existe un moyen canonique de réaliser chaque opération.

Annexe : Encore une fois, voici comment convertir entre org.w3c.dom.Document Et nu.xom.Document. Utilisez les méthodes d'assistance dans la classe DOMConverter de XOM:

// 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
6
Jonik

Si vous utilisez dom4j, vous pouvez simplement faire:

Document document = DocumentHelper.parseText (text);

(dom4j maintenant trouvé ici: https://github.com/dom4j/dom4j )

4
ronz

... et si vous utilisez uniquement XOM, quelque chose comme ceci:

    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 utilise fakeRoot en interne pour faire à peu près la même chose, il devrait donc être sûr, si pas tout à fait élégant.

1
atamar

Essayez jcabi-xml , avec un liner:

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