8

文字列値を使用して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.

あなたの助けに感謝!

4

3 に答える 3

29

ルート要素の名前を変更する簡単な方法はないため、正しい名前空間と属性を持つ要素に置き換えてから、元の子をすべてコピーする必要があります。要素に正しい名前空間(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");
于 2012-06-21T21:23:06.290 に答える
1

ベローアプローチも私には有効ですが、パフォーマンスが重要な場合にはおそらく使用しないでください。

  1. 属性としてドキュメントルート要素に名前空間を追加します。
  2. ドキュメントをXML文字列に変換します。この手順の目的は、XML文字列の子要素が親要素の名前空間を継承するようにすることです。
  3. これで、xml文字列に名前空間ができました。
  4. XML文字列を使用して、ドキュメントを再構築したり、JAXBのアンマーシャルなどに使用したりできます。

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;
}
于 2015-07-01T06:34:56.463 に答える
1

ここから部分的に収集し、上記のコメントからも、それを機能させることができました(任意の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;
  }

それが誰かを助けるなら。次に、それを文字列に変換してから、余分なヘッダーと終了行を手動で削除します。なんて痛い、私は何か間違ったことをしているに違いない...

于 2019-02-22T20:55:00.060 に答える