14

ResultSet を XML ファイルに変換しようとしています。この例を最初にシリアル化に使用しました。

import  org.w3c.dom.bootstrap.DOMImplementationRegistry;
import  org.w3c.dom.Document;
import  org.w3c.dom.ls.DOMImplementationLS;
import  org.w3c.dom.ls.LSSerializer;

...

DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();

DOMImplementationLS impl = 
    (DOMImplementationLS)registry.getDOMImplementation("LS");

...     

LSSerializer writer = impl.createLSSerializer();
String str = writer.writeToString(document);

この作業を行った後、XML ファイルを検証しようとしましたが、いくつかの警告がありました。Doctype がないことについての 1 つ。そこで、これを実装する別の方法を試しました。Transformer クラスに出会いました。このクラスを使用すると、エンコーディング、doctype などを設定できます。

以前の実装では、名前空間の自動修正がサポートされていました。以下はしません。

private static Document toDocument(ResultSet rs) throws Exception {   
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document doc = builder.newDocument();

    URL namespaceURL = new URL("http://www.w3.org/2001/XMLSchema-instance");
    String namespace = "xmlns:xsi="+namespaceURL.toString();

    Element messages = doc.createElementNS(namespace, "messages");
    doc.appendChild(messages);

    ResultSetMetaData rsmd = rs.getMetaData();
    int colCount = rsmd.getColumnCount();

    String attributeValue = "true";
    String attribute = "xsi:nil";

    rs.beforeFirst();

    while(rs.next()) {
        amountOfRecords = 0;
        Element message = doc.createElement("message");
        messages.appendChild(message);

        for(int i = 1; i <= colCount; i++) {

            Object value = rs.getObject(i);
            String columnName = rsmd.getColumnName(i);

            Element messageNode = doc.createElement(columnName);

            if(value != null) {
                messageNode.appendChild(doc.createTextNode(value.toString()));
            } else {
                messageNode.setAttribute(attribute, attributeValue);
            }
            message.appendChild(messageNode);
        }
        amountOfRecords++;
    }
    logger.info("Amount of records archived: " + amountOfRecords);

    TransformerFactory tff = TransformerFactory.newInstance();
    Transformer tf = tff.newTransformer();
    tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
    tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
    tf.setOutputProperty(OutputKeys.INDENT, "yes");

    BufferedWriter bf = createFile();
    StreamResult sr = new StreamResult(bf);
    DOMSource source = new DOMSource(doc);
    tf.transform(source, sr);

    return doc;
}

以前の実装をテストしていたときに、TransformationException: Namespace for prefix 'xsi' has not been defined. が発生しました。ご覧のとおり、xsi プレフィックスを持つ名前空間をドキュメントのルート要素に追加しようとしました。これをテストした後、まだ例外が発生しました。名前空間とそのプレフィックスを設定する正しい方法は何ですか?

編集: 最初の実装で私が抱えていたもう 1 つの問題は、XML ドキュメントの最後の要素に最後の 3 つの終了タグがないことです。

4

3 に答える 3

34

namespaceAware ドキュメントにノードを設定する正しい方法は、次を使用することです。

rootNode.createElementNS("http://example/namespace", "PREFIX:aNodeName");

したがって、「PREFIX」を独自のカスタム プレフィックスに置き換え、「aNodeName」をノードの名前に置き換えることができます。各ノードが独自の名前空間宣言を持つことを避けるために、次のように名前空間をルート ノードの属性として定義できます。

rootNode.setAttribute("xmlns:PREFIX", "http://example/namespace");

必ず設定してください:

documentBuilderFactory.setNamespaceAware(true)

そうしないと、namespaceAwareness がありません。

于 2012-10-24T11:41:43.673 に答える
10

setAttribute で xmlns-prefix を設定するのは間違っていることに注意してください。たとえば、DOM に署名したい場合は、setAttributeNS を使用する必要があります。 element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:PREFIX", "http://example/namespace");

于 2014-10-16T07:18:30.090 に答える
9

ルート ノードに名前空間宣言を追加していません。名前空間でルート ノードを宣言しただけで、2 つのまったく異なるものです。DOM を構築するときは、関連するすべてのノードで名前空間を参照する必要があります。つまり、属性を追加するときは、その名前空間 (setAttributeNS など) を定義する必要があります。

補足: XML 名前空間は URL のように見えますが、実際にはそうではありません。ここで URL クラスを使用する必要はありません。

于 2012-05-14T14:20:06.843 に答える