Як на Java можна перетворити рядок, який представляє фрагмент XML, для вставки в документ XML?
напр
String newNode = "<node>value</node>"; // Convert this to XML
Потім вставити цей вузол в org.w3c.dom.Document як дочірній матеріал даного вузла?
Як на Java можна перетворити рядок, який представляє фрагмент XML, для вставки в документ XML?
напр
String newNode = "<node>value</node>"; // Convert this to XML
Потім вставити цей вузол в org.w3c.dom.Document як дочірній матеріал даного вузла?
Відповіді:
Element node = DocumentBuilderFactory
.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream("<node>value</node>".getBytes()))
.getDocumentElement();
Ви можете використовувати метод імпорту (або прийняття ) документа, щоб додати фрагменти 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);
}
Для чого це варте, ось рішення, яке я придумав, використовуючи бібліотеку 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; детальніше читайте у зв’язаному вище запитанні.
Ось ще одне рішення, яке використовує бібліотеку 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
/**
*
* 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;
}
Якщо ви використовуєте dom4j, ви можете просто зробити:
Документ документа = DocumentHelper.parseText (текст);
(dom4j зараз знайдено тут: https://github.com/dom4j/dom4j )
... а якщо ви використовуєте суто 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 внутрішньо, щоб робити майже те саме, тому він повинен бути безпечним, якщо не зовсім елегантним.
Спробуйте jcabi-xml , з одним вкладишем:
Node node = new XMLDocument("<node>value</node>").node();
Unresolved references to [com.jcabi.xml] by class(es) on the Bundle-Classpath[Jar:dot]