Перетворити фрагмент рядка XML у вузол документа на Java


77

Як на Java можна перетворити рядок, який представляє фрагмент XML, для вставки в документ XML?

напр

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

Потім вставити цей вузол в org.w3c.dom.Document як дочірній матеріал даного вузла?


Дивіться також: stackoverflow.com/a/7607435/363573
— Стефан

Відповіді:


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

3
.parse (new StringInputStream (.... повинен читати .parse (new ByteArrayInputStream (new String ("xml") .getBytes ()));
— Стін

5
Я просто ненавиджу ці скриньки коментарів та їх відсутність розмітки (або, натомість, націнки)
— Стін,

4
але це не копіює дітей ... наприклад, якщо ви зробите це у випадку "<tag1> <tag2> <tag3> blah </tag3> blah </tag2> </tag1> Це отримує лише <tag1> без його діти
— гробартн

1
Це не спрацювало для мене, оскільки не копіювало дітей, як зазначив Гробартн. Рішення @ McDowell справді спрацювало.
— Upgradingdave

33

Ви можете використовувати метод імпорту (або прийняття ) документа, щоб додати фрагменти 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
Хм Якщо це найпростіше рішення, я повинен сказати, що воно досить складне для такої невеликої проблеми.
— Джонік

Я звів його до мінімуму - він все одно використовує те, що ви отримуєте в JRE API, однак, трохи деталізації не уникнути.
— McDowell

3
Це саме те, що я шукав. Я не розумів, що повинен імпортувати фрагмент у dom, перш ніж додавати його до батьківського вузла!
— Tony Eichelberger

Якщо багатослів'я ви не хочете, ви не повинні використовувати Java, Лука. Дякую за відповідь, ніхто не має шансів це зрозуміти.
— Акку

Незважаючи на те, що вибрана відповідь є правильною, враховуючи те, що запитав користувач, цей ансер є "більш" правильним.
— chessofnerd

15

Для чого це варте, ось рішення, яке я придумав, використовуючи бібліотеку 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));

Потім отримайте Документ, до якого вставлений новий вузол, і батьківський Елемент (який має бути) з нього. (Ваш 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; детальніше читайте у зв’язаному вище запитанні.


Якщо dom4j NO-GO, спробуйте таке рішення: stackoverflow.com/a/7607435/363573
— Стефан

6

Ось ще одне рішення, яке використовує бібліотеку XOM , яке конкурує з моєю відповіддю dom4j . (Це частина мого прагнення знайти хорошу заміну dom4j, де XOM був запропонований як один із варіантів.)

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

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

Потім отримайте документ і вузол, під який додано фрагмент. Знову ж таки, для цілей тестування я буду створювати документ із рядка:

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

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

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

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

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

(Якщо ви хочете красиво відформатувати XML (із відступами та подачами рядків), використовуйте a Serializer; спасибі Пітеру Штібрані за те, що на це вказав.)

Тож слід визнати, що це не сильно відрізняється від рішення dom4j. :) Однак, з XOM може бути дещо приємніше працювати, тому що API краще задокументований, і завдяки його філософії дизайну існує один канонічний спосіб зробити кожну справу.

Додаток : Знову, ось як перетворити між org.w3c.dom.Documentі nu.xom.Document. Використовуйте допоміжні методи в DOMConverterкласі 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

Зверніть увагу, що замість new Builder (). Build (new StringReader ("<root> <given> </given> </root>")); Ви також можете використовувати new Builder (). build ("<root> <given> </given> </root>", "test.xml"); (де "test.xml" - це якийсь випадковий базовий URI)
— Peter Štibraný

1
"Якщо ви хочете красиво відформатувати XML (із відступами та подачами рядків), я не впевнений, як це зробити за допомогою XOM." - за допомогою класу Serializer. Налаштуйте його, використовуючи setIndent і setMaxLength, і викличте запис (документ).
— Peter Štibraný

Серіалізатор також легко налаштувати, підкласуючи.
— Peter Štibraný

Дякую! Я насправді не розумів, що саме означає параметр baseURI; передача порожнього рядка також працює, тому я використовую це. У будь-якому випадку це дещо спрощує код. Що стосується форматування, Serializer справді чудово працює.
— Jonik

Я думаю, що baseURI буде використовуватися для вирішення відносних посилань на DTD або XInclude ( lists.ibiblio.org/pipermail/xom-interest/2004-November/… )
— Пітер Штібрані,

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

4

Якщо ви використовуєте dom4j, ви можете просто зробити:

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

(dom4j зараз знайдено тут: https://github.com/dom4j/dom4j )


Просто зайшов на їх веб-сайт. Вони розміщують Google Ads прямо на типовій навігаційній панелі, створеній Maven! Неймовірно!
— Тіло

2
Очевидно, що сайт більше не експлуатується хлопцями dom4j, але деякі захопники доменів захопили ...
— Тіло

1

... а якщо ви використовуєте суто 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 внутрішньо, щоб робити майже те саме, тому він повинен бути безпечним, якщо не зовсім елегантним.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.