2

私は、任意の (または少なくとも整形式の) XML ファイルを読み取り、いくつかのノードを操作して、それらを同じファイルに書き戻すことができるシステムに取り組んでいます。コードをできるだけ汎用的にしたいのですが、そうしたくありません

  • コード内の任意の場所にスキーマ/Doctype 情報への参照をハードコーディングしました。doctype 情報はソース ドキュメントにあります。その doctype 情報を正確に保持し、コード内から再度提供したくありません。ドキュメントに DocType がない場合は、追加しません。いくつかのノードを除いて、これらのファイルの形式や内容はまったく気にしません。
  • カスタム EntityResolvers または StreamFilters を使用して、ソース情報を省略または操作します (名前空間情報が宣言されているドキュメント ファイルから何らかの形でアクセスできないように見えるのは残念ですが、より醜い XPath を使用して管理できます)。
  • DTD 検証。私は参照された DTD を持っていません。それらを含めたくありません。ノード操作は、それらについて知らなくても完全に可能です。

目的は、XPath 経由で取得される変更されたノードを除いて、ソース ファイルを完全に変更しないことです。標準の javax.xml を使いこなしたいと思います。

これまでの私の進捗状況:

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    factory.setAttribute("http://xml.org/sax/features/namespaces", true);
    factory.setAttribute("http://xml.org/sax/features/validation", false);
    factory.setAttribute("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
    factory.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

    factory.setNamespaceAware(true);
    factory.setIgnoringElementContentWhitespace(false);
    factory.setIgnoringComments(false);
    factory.setValidating(false);
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document document = builder.parse(new InputSource(inStream));

これにより、XML ソースが org.w3c.dom.Document に正常にロードされ、DTD 検証が無視されます。私は自分の交換を行うことができ、それから私は使用します

    Source source = new DOMSource(document);
    Result result = new StreamResult(getOutputStream(getPath()));

    // Write the DOM document to the file
    Transformer xformer = TransformerFactory.newInstance().newTransformer();
    xformer.transform(source, result);

それを書き戻す。これはほぼ完璧です。しかし、何をしてもDoctypeタグはなくなりました。デバッグ中に、解析後に Document オブジェクトに DeferredDoctypeImpl [log4j:configuration: null] オブジェクトがあることがわかりましたが、何らかの理由で間違っているか、空であるか、無視されています。テストしたファイルは次のように始まります (ただし、他のファイル タイプでも同じです)。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE log4j:構成システム "log4j.dtd">

<log4j:構成 xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">

[...]

ハッキングやプロジェクトへの追加の JAR のプルを含む (簡単な?) 方法はたくさんあると思います。しかし、私はむしろ、すでに使用しているツールでそれを使用したいと考えています.

4

3 に答える 3

1

申し訳ありませんが、トランスフォーマーの代わりに XMLSerializer を使用して今すぐ取得しました...

于 2009-02-24T16:29:03.920 に答える
0

JDK にある LSSerializer を使用してそれを行う方法は次のとおりです。

    private void writeDocument(Document doc, String filename)
            throws IOException {
        Writer writer = null;
        try {
            /*
             * Could extract "ls" to an instance attribute, so it can be reused.
             */
            DOMImplementationLS ls = (DOMImplementationLS) 
                    DOMImplementationRegistry.newInstance().
                            getDOMImplementation("LS");
            writer = new OutputStreamWriter(new FileOutputStream(filename));
            LSOutput lsout = ls.createLSOutput();
            lsout.setCharacterStream(writer);
            /*
             * If "doc" has been constructed by parsing an XML document, we
             * should keep its encoding when serializing it; if it has been
             * constructed in memory, its encoding has to be decided by the
             * client code.
             */
            lsout.setEncoding(doc.getXmlEncoding());
            LSSerializer serializer = ls.createLSSerializer();
            serializer.write(doc, lsout);
        } catch (Exception e) {
            throw new IOException(e);
        } finally {
            if (writer != null) writer.close();
        }
    }

必要なインポート:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import org.w3c.dom.Document;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;

これはすでに回答されている古い質問であることは知っていますが、技術的な詳細が誰かの助けになると思います.

于 2011-03-01T11:59:22.063 に答える