Преобразование XML-фрагмента String в документ Node в Java

В Java как можно преобразовать строку, представляющую фрагмент XML для вставки в документ XML?

например.

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

Затем вставьте этот node в org.w3c.dom.Document как дочерний элемент данного node?

Ответ 1

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

Ответ 2

Вы можете использовать документ import (или adopt) для добавления фрагментов 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);
  }

Ответ 3

Для чего стоит, вот решение, которое я придумал, используя библиотеку dom4j. (Я действительно проверял, что он работает.)

Прочитайте фрагмент XML в org.dom4j.Document (обратите внимание: все классы XML, используемые ниже, из org.dom4j, см. Приложение):

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

Затем получите документ, в который вставлен новый node, и родительский элемент (из него). (Ваш org.w3c.dom.Document должен быть преобразован в org.dom4j.Document здесь.) Для целей тестирования я создал такой вот:

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

Добавление нового дочернего элемента очень просто:

    givenNode.add(newNodeDocument.getRootElement());

Готово. Вывод originalDoc теперь дает:

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

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

Приложение. Поскольку ваш вопрос говорит о org.w3c.dom.Document, вот как конвертировать между этим и 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);

(Если вам понадобится использовать оба типа Document регулярно, может быть целесообразно включить их в опрятные утилиты, возможно, в класс под названием XMLUtils или что-то в этом роде.)

Возможно, есть лучшие способы сделать это, даже без каких-либо сторонних библиотек. Но из представленных на данный момент решений, на мой взгляд, это самый простой способ, даже если вам нужно сделать преобразования dom4j ↔ w3c.

Обновить (2011): перед добавлением зависимости dom4j к вашему коду, обратите внимание, что это не активно поддерживаемый проект, а также некоторые другие проблемы. Улучшенная версия 2.0 работает уже давно, но доступна только альфа-версия. Вместо этого вы можете рассмотреть альтернативу, например XOM; прочитайте больше в связанном выше вопросе.

Ответ 4

Здесь еще одно решение, использующее XOM библиотека, которая конкурирует с my dom4j answer. (Это часть моего поиска, чтобы найти хорошую замену dom4j, где XOM был предложен как один из вариантов.)

Сначала прочитайте фрагмент XML в nu.xom.Document:

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

Затем получите документ и Node, в которые добавлен фрагмент. Опять же, для тестирования я создам документ из строки:

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

Теперь добавление дочернего элемента Node прост и схож с dom4j (кроме того, что XOM не позволяет добавить исходный корневой элемент, который уже принадлежит newNodeDocument):

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

Вывод документа дает правильный результат XML (и с XOM замечательно просто: просто напечатайте строку, возвращаемую originalDoc.toXML()):

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

(Если вы хотите отформатировать XML красиво (с углублениями и переводами строк), используйте Serializer, благодаря Peter Štibraný для указывая это.)

Итак, по общему признанию, это не сильно отличается от решения dom4j.:) Тем не менее, XOM может быть немного приятнее в работе, потому что API лучше документирован, и из-за его философии дизайна существует один канонический способ выполнения каждой вещи.

Приложение: здесь, здесь, как конвертировать между org.w3c.dom.Document и nu.xom.Document. Используйте вспомогательные методы в классе 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

Ответ 5

Если вы используете dom4j, вы можете просто сделать:

Документ document = DocumentHelper.parseText(текст);

(dom4j теперь находится здесь: https://github.com/dom4j/dom4j)

Ответ 6

/**
*
* 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;
}

Ответ 7

... и если вы используете чисто XOM, что-то вроде этого:

    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 использует fakeRoot внутренне, чтобы сделать почти то же самое, поэтому он должен быть безопасным, если не совсем изящным.

Ответ 8

Попробуйте jcabi-xml с одним слоем:

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