tohokuaikiのチラシの裏

技術的ネタとか。

SaxonでDTDチェックする

本来はこういう使い方はしないんだろうけど、SaxonをDTDバリデータとして使ってみる。Saxonは8.7.

// 対象となるXML
String xml = "<?xml....."; 
// 何もしないXSL
String noopXsl = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><xsl:stylesheet version=\"2.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"></xsl:stylesheet>";
try {
    StreamSource xslSource = new StreamSource(new ByteArrayInputStream(noopXsl.getBytes("UTF-8")));
    StreamSource xmlSource = new StreamSource(new ByteArrayInputStream(xml.getBytes("UTF-8")));
    /// エラー時の出力をByteArrayOutputStreamで受けるようなSaxonのFactoryクラスを作成する
    // factoryの設定を行うObjectを作成
    Configuration saConfig = new net.sf.saxon.Configuration();
    // エラーリスナーのOutputする先をバイトストリームにする
    StandardErrorListener se = new net.sf.saxon.StandardErrorListener();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    PrintStream ps = new PrintStream(baos);
    // Objectをセット
    se.setErrorOutput(ps);
    saConfig.setErrorListener(se);
    // factory作成
    TransformerFactory tFactory = new net.sf.saxon.TransformerFactoryImpl(saConfig);
    /**
     * ファクトリのDTDチェックをONにする。設定できるものは、net.sf.saxon.FeatureKeysにありそう
     */
    tFactory.setAttribute(FeatureKeys.DTD_VALIDATION, true);
    Transformer transformer = tFactory.newTransformer(xslSource);
    transformer.transform(xmlSource, new StreamResult(new StringWriter()));
    // baos.size()が0ならDTDエラーは無い。
    if (baos.size() > 0){
        System.out.println(baos);
    }
    baos.close();
    ps.close();
} catch (UnsupportedEncodingException ex) {
} catch (TransformerConfigurationException ex) {
} catch (TransformerException ex) {
} catch (IOException ex) {
}

tFactory.setAttribute()で何が使えるかというと、Saxonをコマンドラインで動かしてみて

$ java -jar saxonb9/saxon9.jar
No source file name
Saxon 9.1.0.8J from Saxonica
Usage: see http://www.saxonica.com/documentation/using-xsl/commandline.html
Options:
  -a                    Use xml-stylesheet PI, not style-doc argument
  -c:filename           Use compiled stylesheet from file
  -cr:classname         Use collection URI resolver class
  -dtd:on|off           Validate using DTD
  -expand:on|off        Expand defaults defined in schema/DTD
  -explain[:filename]   Display compiled expression tree
  -ext:on|off           Allow|Disallow external Java functions
  -im:modename          Initial mode
  -it:template          Initial template
  -l:on|off             Line numbering for source document
  -m:classname          Use message receiver class
  -o:filename           Output file or directory
  -or:classname         Use OutputURIResolver class
  -outval:recover|fatal Handling of validation errors on result document
  -p:on|off             Recognize URI query parameters
  -r:classname          Use URIResolver class
  -repeat:N             Repeat N times for performance measurement
  -s:filename           Initial source document
  -sa                   Schema-aware transformation
  -strip:all|none|ignorable      Strip whitespace text nodes
  -t                    Display version and timing information
  -T[:classname]        Use TraceListener class
  -TJ                   Trace calls to external Java functions
  -tree:tiny|linked     Select tree model
  -traceout:file|#null  Destination for fn:trace() output
  -u                    Names are URLs not filenames
  -val:strict|lax       Validate using schema
  -versionmsg:on|off    Warn when using XSLT 1.0 stylesheet
  -warnings:silent|recover|fatal  Handling of recoverable errors
  -x:classname          Use specified SAX parser for source file
  -xi:on|off            Expand XInclude on all documents
  -xmlversion:1.0|1.1   Version of XML to be handled
  -xsd:file;file..      Additional schema documents to be loaded
  -xsdversion:1.0|1.1   Version of XML Schema to be used
  -xsiloc:on|off        Take note of xsi:schemaLocation
  -xsl:filename         Stylesheet file
  -y:classname          Use specified SAX parser for stylesheet
  -?                    Display this message
  param=value           Set stylesheet string parameter
  +param=filename       Set stylesheet document parameter
  !option=value         Set serialization option

これらのOptionなら設定できそうである。

Saxonを9.7にしてみる

Saxon9.7にすると、上記の方法だとエラーが出る。
主にエラー出力のハンドリング回り。

// この2つはlibのパッケージは以下になった
import net.sf.saxon.lib.FeatureKeys;
import net.sf.saxon.lib.StandardErrorListener;
// Loggerクラスを備えるようになった。
import net.sf.saxon.lib.StandardLogger;

...
StandardErrorListener se = new StandardErrorListener();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
se.setLogger(new StandardLogger(ps));

// se.setErrorOutput(ps);
se.setLogger(new StandardLogger(ps));

StandardErrorListenerの方向をsetErrorOutputではなく、setLoggerメソッドでLoggerオブジェクトを渡すことで設定する。