Java : LSSerializer (XML) - API使用例
LSSerializer (Java SE 22 & JDK 22) の使い方まとめです。
 ほとんどのメソッドにサンプルコードがあります。
 API仕様書のおともにどうぞ。
概要
LSSerializerは、DOM文書をXMLに直列化する(書き込む)ためのAPIを提供します。 XMLデータは文字列または出力ストリームに書き込まれます。 直列化を実行する間にどのような変更や修正が行われても、影響があるのは直列化されたデータだけです。 Documentオブジェクトとその子が直列化操作によって変更されることはありません。
DOMを文字列に変換するには、よく Transformer が使われます。
 ただし、Transformer は汎用的に設計されたAPIのため、DocumentType や EntityReference が思うように変換できないこともあるかもしれません。
一方、DOMLS の LSSerializer を使えば DocumentType や EntityReference をそのまま出力できます。
関連記事 : XML (DOM) の基本操作
final var xml = """
        <!DOCTYPE root [
            <!ENTITY aaa "bbb">
        ]>
        <root>&aaa;</root>
        """;
final var factory = DocumentBuilderFactory.newInstance();
factory.setExpandEntityReferences(false);
final var builder = factory.newDocumentBuilder();
final var document = builder.parse(new ByteArrayInputStream(xml.getBytes()));
final var domImpl = builder.getDOMImplementation();
final var feature = domImpl.getFeature("LS", "3.0");
if (feature instanceof DOMImplementationLS ls) {
    final var serializer = ls.createLSSerializer();
    final var str = serializer.writeToString(document);
    System.out.println(str);
    // 結果
    // ↓
    //<?xml version="1.0" encoding="UTF-16"?><!DOCTYPE root [
    //<!ENTITY aaa 'bbb'>
    //]>
    //<root>&aaa;</root>
}
 
メソッド
DOMConfiguration getDomConfig ()
DOMノードの直列化中にLSSerializerが使用するDOMConfigurationオブジェクト。
final var factory = DocumentBuilderFactory.newInstance();
final var builder = factory.newDocumentBuilder();
final var domImpl = builder.getDOMImplementation();
final var feature = domImpl.getFeature("LS", "3.0");
if (feature instanceof DOMImplementationLS ls) {
    final var serializer = ls.createLSSerializer();
    final var domConfig = serializer.getDomConfig();
    final var names = domConfig.getParameterNames();
    for (int i = 0; i < names.getLength(); i++) {
        final var name = names.item(i);
        final var param = domConfig.getParameter(name);
        System.out.println(name + " : " + param);
    }
    // 結果
    // ↓
    //canonical-form : false
    //cdata-sections : true
    //check-character-normalization : false
    //comments : true
    //datatype-normalization : false
    //element-content-whitespace : true
    //entities : true
    //infoset : false
    //namespaces : true
    //namespace-declarations : true
    //split-cdata-sections : true
    //validate : false
    //validate-if-schema : false
    //well-formed : true
    //discard-default-content : true
    //format-pretty-print : false
    //ignore-unknown-character-denormalizations : true
    //xml-declaration : true
    //http://www.oracle.com/xml/jaxp/properties/isStandalone : false
    //jdk.xml.isStandalone : false
    //error-handler : null
}
 
      LSSerializerFilter getFilter ()
アプリケーションでフィルタが用意されていると、直列化処理は各ノードを直列化する前にフィルタを呼び出します。
final var factory = DocumentBuilderFactory.newInstance();
final var builder = factory.newDocumentBuilder();
final var domImpl = builder.getDOMImplementation();
final var feature = domImpl.getFeature("LS", "3.0");
if (feature instanceof DOMImplementationLS ls) {
    final var xml = """
            <root>
              <child><aaa/><bbb/><ccc/></child>
            </root>
            """;
    final var input = ls.createLSInput();
    input.setStringData(xml);
    final var parser = ls.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
    final var document = parser.parse(input);
    final var serializer = ls.createLSSerializer();
    System.out.println(serializer.getFilter()); // null
    //<?xml version="1.0" encoding="UTF-16"?><root>
    //  <child><aaa/><bbb/><ccc/></child>
    //</root>
    System.out.println(serializer.writeToString(document));
    final var filter = new LSSerializerFilter() {
        @Override
        public short acceptNode(Node n) {
            System.out.println("acceptNode : " + n);
            if (n.getNodeName().equals("bbb")) {
                return NodeFilter.FILTER_REJECT;
            } else {
                return NodeFilter.FILTER_ACCEPT;
            }
        }
        @Override
        public int getWhatToShow() {
            return NodeFilter.SHOW_ELEMENT;
        }
    };
    serializer.setFilter(filter);
    System.out.println(filter == serializer.getFilter()); // true
    System.out.println("-- write start --");
    final var ret = serializer.writeToString(document);
    System.out.println("-- write end --");
    System.out.println(ret);
    // 結果
    // ↓
    //-- write start --
    //acceptNode : [root: null]
    //acceptNode : [child: null]
    //acceptNode : [aaa: null]
    //acceptNode : [aaa: null]
    //acceptNode : [bbb: null]
    //acceptNode : [bbb: null]
    //acceptNode : [ccc: null]
    //acceptNode : [ccc: null]
    //acceptNode : [child: null]
    //acceptNode : [root: null]
    //-- write end --
    //<?xml version="1.0" encoding="UTF-16"?><root>
    //  <child><aaa/><ccc/></child>
    //</root>
}
 
      String getNewLine ()
書き出されているXMLで使用される行末シーケンス文字です。
final var factory = DocumentBuilderFactory.newInstance();
final var builder = factory.newDocumentBuilder();
final var domImpl = builder.getDOMImplementation();
final var feature = domImpl.getFeature("LS", "3.0");
if (feature instanceof DOMImplementationLS ls) {
    final var serializer = ls.createLSSerializer();
    final var ret1 = serializer.getNewLine();
    System.out.println(Arrays.toString(ret1.getBytes())); // [10]
    System.out.println(ret1.equals("\n")); // true
    serializer.setNewLine("\r\n");
    final var ret2 = serializer.getNewLine();
    System.out.println(Arrays.toString(ret2.getBytes())); // [13, 10]
    System.out.println(ret2.equals("\r\n")); // true
}
 
      void setFilter (LSSerializerFilter filter)
アプリケーションでフィルタが用意されていると、直列化処理は各ノードを直列化する前にフィルタを呼び出します。
final var factory = DocumentBuilderFactory.newInstance();
final var builder = factory.newDocumentBuilder();
final var domImpl = builder.getDOMImplementation();
final var feature = domImpl.getFeature("LS", "3.0");
if (feature instanceof DOMImplementationLS ls) {
    final var xml = """
            <root>
              <child><aaa/><bbb/><ccc/></child>
            </root>
            """;
    final var input = ls.createLSInput();
    input.setStringData(xml);
    final var parser = ls.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
    final var document = parser.parse(input);
    final var serializer = ls.createLSSerializer();
    System.out.println(serializer.getFilter()); // null
    //<?xml version="1.0" encoding="UTF-16"?><root>
    //  <child><aaa/><bbb/><ccc/></child>
    //</root>
    System.out.println(serializer.writeToString(document));
    final var filter = new LSSerializerFilter() {
        @Override
        public short acceptNode(Node n) {
            System.out.println("acceptNode : " + n);
            if (n.getNodeName().equals("bbb")) {
                return NodeFilter.FILTER_REJECT;
            } else {
                return NodeFilter.FILTER_ACCEPT;
            }
        }
        @Override
        public int getWhatToShow() {
            return NodeFilter.SHOW_ELEMENT;
        }
    };
    serializer.setFilter(filter);
    System.out.println(filter == serializer.getFilter()); // true
    System.out.println("-- write start --");
    final var ret = serializer.writeToString(document);
    System.out.println("-- write end --");
    System.out.println(ret);
    // 結果
    // ↓
    //-- write start --
    //acceptNode : [root: null]
    //acceptNode : [child: null]
    //acceptNode : [aaa: null]
    //acceptNode : [aaa: null]
    //acceptNode : [bbb: null]
    //acceptNode : [bbb: null]
    //acceptNode : [ccc: null]
    //acceptNode : [ccc: null]
    //acceptNode : [child: null]
    //acceptNode : [root: null]
    //-- write end --
    //<?xml version="1.0" encoding="UTF-16"?><root>
    //  <child><aaa/><ccc/></child>
    //</root>
}
 
      void setNewLine (String newLine)
書き出されているXMLで使用される行末シーケンス文字です。
final var factory = DocumentBuilderFactory.newInstance();
final var builder = factory.newDocumentBuilder();
final var domImpl = builder.getDOMImplementation();
final var feature = domImpl.getFeature("LS", "3.0");
if (feature instanceof DOMImplementationLS ls) {
    final var serializer = ls.createLSSerializer();
    final var ret1 = serializer.getNewLine();
    System.out.println(Arrays.toString(ret1.getBytes())); // [10]
    System.out.println(ret1.equals("\n")); // true
    serializer.setNewLine("\r\n");
    final var ret2 = serializer.getNewLine();
    System.out.println(Arrays.toString(ret2.getBytes())); // [13, 10]
    System.out.println(ret2.equals("\r\n")); // true
}
 
      boolean write (Node nodeArg, LSOutput destination)
LSSerializerインタフェースの一般的な説明で、前述のように指定されたノードを直列化します。
final var factory = DocumentBuilderFactory.newInstance();
final var builder = factory.newDocumentBuilder();
final var domImpl = builder.getDOMImplementation();
final var feature = domImpl.getFeature("LS", "3.0");
if (feature instanceof DOMImplementationLS ls) {
    final var document = builder.newDocument();
    final var root = document.createElement("root");
    document.appendChild(root);
    final var text = document.createTextNode("abcd");
    root.appendChild(text);
    final var path = Path.of("R:", "java-work", "sample.xml");
    System.out.println(path); // R:\java-work\sample.xml
    try (final var writer = Files.newBufferedWriter(path)) {
        final var destination = ls.createLSOutput();
        destination.setCharacterStream(writer);
        final var serializer = ls.createLSSerializer();
        final var ret = serializer.write(document, destination);
        System.out.println(ret); // true
    }
    //<?xml version="1.0" encoding="UTF-8"?><root>abcd</root>
    System.out.println(Files.readString(path));
}
 
      String writeToString (Node nodeArg)
LSSerializerインタフェースの一般的な説明で、前述のように指定されたノードを直列化します。
final var factory = DocumentBuilderFactory.newInstance();
final var builder = factory.newDocumentBuilder();
final var domImpl = builder.getDOMImplementation();
final var feature = domImpl.getFeature("LS", "3.0");
if (feature instanceof DOMImplementationLS ls) {
    final var document = builder.newDocument();
    final var root = document.createElement("root");
    document.appendChild(root);
    final var text = document.createTextNode("abcd");
    root.appendChild(text);
    final var serializer = ls.createLSSerializer();
    final var str = serializer.writeToString(document);
    //<?xml version="1.0" encoding="UTF-16"?><root>abcd</root>
    System.out.println(str);
}
 
      boolean writeToURI (Node nodeArg, String uri)
エンコーディングを指定せず、LSOutput.systemIdをuri引数に設定して、LSOutputでLSSerializer.writeが呼び出されたかのように機能する簡易メソッドです。
final var factory = DocumentBuilderFactory.newInstance();
final var builder = factory.newDocumentBuilder();
final var domImpl = builder.getDOMImplementation();
final var feature = domImpl.getFeature("LS", "3.0");
if (feature instanceof DOMImplementationLS ls) {
    final var document = builder.newDocument();
    final var root = document.createElement("root");
    document.appendChild(root);
    final var text = document.createTextNode("abcd");
    root.appendChild(text);
    final var path = Path.of("R:", "java-work", "sample.xml");
    System.out.println(path); // R:\java-work\sample.xml
    final var uri = path.toUri();
    System.out.println(uri); // file:///R:/java-work/sample.xml
    final var serializer = ls.createLSSerializer();
    final var ret = serializer.writeToURI(document, uri.toString());
    System.out.println(ret); // true
    //<?xml version="1.0" encoding="UTF-8"?><root>abcd</root>
    System.out.println(Files.readString(path));
}
 
      


