Добавление пространства имен в уже созданный XML-документ

Я создаю объект документа W3C, используя строковое значение. Создав объект Document, я хочу добавить пространство имен к корневому элементу этого документа. Вот мой текущий код:

Document document = builder.parse(new InputSource(new StringReader(xmlString)));
document.getDocumentElement().setAttributeNS("http://com", "xmlns:ns2", "Test");
document.setPrefix("ns2");
TransformerFactory tranFactory = TransformerFactory.newInstance();
Transformer aTransformer = tranFactory.newTransformer();
Source src = new DOMSource(document);
Result dest = new StreamResult(new File("c:\\xmlFileName.xml"));
aTransformer.transform(src, dest);

Что я использую в качестве ввода:

<product>
    <arg0>DDDDDD</arg0>
    <arg1>DDDD</arg1>
</product>

Как должен выглядеть вывод:

<ns2:product xmlns:ns2="http://com">
    <arg0>DDDDDD</arg0>
    <arg1>DDDD</arg1>
</ns2:product>

Мне нужно добавить значение префикса и пространство имен также во входную строку XML. Если я попробую приведенный выше код, я получу это исключение:

NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.

Ценю твою помощь!

 rolve21 июн. 2012 г., 11:03
Вашbuilder пространства имен в курсе?builder.isNamespaceAware()

Ответы на вопрос(3)

Решение Вопроса

нам придется заменить его элементом, который имеет правильное пространство имен и атрибут, а затем скопировать в него все исходные дочерние элементы. Принудительное объявление пространства имен не требуется, потому что, предоставив элементу правильное пространство имен (URI) и установив префикс, объявление будет автоматическим.

ЗаменитьsetAttribute а такжеsetPrefix с этим (строка 2,3)

String namespace = "http://com";
String prefix = "ns2";
// Upgrade the DOM level 1 to level 2 with the correct namespace
Element originalDocumentElement = document.getDocumentElement();
Element newDocumentElement = document.createElementNS(namespace, originalDocumentElement.getNodeName());
// Set the desired namespace and prefix
newDocumentElement.setPrefix(prefix);
// Copy all children
NodeList list = originalDocumentElement.getChildNodes();
while(list.getLength()!=0) {
    newDocumentElement.appendChild(list.item(0));
}
// Replace the original element
document.replaceChild(newDocumentElement, originalDocumentElement);

В исходном коде автор попытался объявить пространство имен элемента следующим образом:

.setAttributeNS("http://com", "xmlns:ns2", "Test");

Первый параметр представляет собой пространство имен атрибута, и, поскольку он является атрибутом пространства имен, он должен иметьhttp://www.w3.org/2000/xmlns/ URI. Объявленное пространство имен должно входить в 3-й параметр

.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns2", "http://com");
 27 нояб. 2014 г., 16:51
Большое спасибо! Это действительно помогло мне, в моем случае пространство имен никогда не включалось в расчет дайджеста, потому что я добавил его как обычный атрибут вместо того, чтобы добавить его как реальное пространство имен. +1
 16 нояб. 2018 г., 02:53
Префикс обычно не важен. У меня были проблемы при использованииreplaceChild() (возможно, я что-то не так сделал), но, похоже, проще просто переименовать узел:doc.renameNode(doc.getDocumentElement(), nameSpaceNeeded, doc.getDocumentElement().getTagName());
 01 июл. 2015 г., 08:26
Похоже, этот подход не может добавить одно и то же пространство имен к дочернему элементу, поэтому я использую этот подход, затем генерирую строку XML из документа и снова анализирую созданную строку XML.

но, вероятно, не следует использовать в случае критической производительности.

Add name space to document root element as attribute. Transform the document to XML string. The purpose of this step is to make the child element in the XML string inherit parent element namespace. Now the xml string have name space. You can use the XML string to build a document again or used for JAXB unmarshal, etc.
private static String addNamespaceToXml(InputStream in)
        throws ParserConfigurationException, SAXException, IOException,
        TransformerException {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    /*
     * Must not namespace aware, otherwise the generated XML string will
     * have wrong namespace
     */
    // dbf.setNamespaceAware(true);
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document document = db.parse(in);
    Element documentElement = document.getDocumentElement();
    // Add name space to root element as attribute
    documentElement.setAttribute("xmlns", "http://you_name_space");
    String xml = transformXmlNodeToXmlString(documentElement);
    return xml;
}

private static String transformXmlNodeToXmlString(Node node)
        throws TransformerException {
    TransformerFactory transFactory = TransformerFactory.newInstance();
    Transformer transformer = transFactory.newTransformer();
    StringWriter buffer = new StringWriter();
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
    transformer.transform(new DOMSource(node), new StreamResult(buffer));
    String xml = buffer.toString();
    return xml;
}

Воти также из приведенного выше комментария я смог заставить его работать (преобразовав произвольный узел DOM и добавив префикс к нему и всем его дочерним элементам), таким образом:

  private String addNamespacePrefix(Document doc, Node node) throws TransformerException {
    Element mainRootElement = doc.createElementNS(
            "http://abc.de/x/y/z", // namespace
            "my-prefix:fake-header-element" // prefix to "register" it with the DOM so we don't get exceptions later...
    );
    List<Element> descendants = nodeListToArrayRecurse(node.getChildNodes()); // for some reason we have to grab all these before doing the first "renameNode" ... no idea why ...

    mainRootElement.appendChild(node);
    doc.renameNode(node, "http://abc.de/x/y/z", "my-prefix:" + node.getNodeName());
    descendants.stream().forEach(c -> doc.renameNode(c, "http://abc.de/x/y/z", "my-prefix:" + c.getNodeName()));
  }

  private List<Element> nodeListToArrayRecurse(NodeList entryNodes) {
    List<Element> allEntries = new ArrayList<>();
    for (int i = 0; i < entryNodes.getLength(); i++) {
      Node child = entryNodes.item(i);
      if (child.getNodeType() == Node.ELEMENT_NODE) {
        allEntries.add((Element) child);
        allEntries.addAll(nodeListToArray(child.getChildNodes())); // recurse
      } // ignore other [i.e. text] nodes https://stackoverflow.com/questions/14566596/loop-through-all-elements-in-xml-using-nodelist
    }
    return allEntries;
  }

Если это кому-нибудь поможет. Затем я конвертирую его в строку, затем вручную удаляю лишний заголовок и закрывающие строки.

Ваш ответ на вопрос