web-dev-qa-db-ja.com

Java)を使用してローカルDTDファイルに対してXMLファイルを検証します

ローカルにファイルとして保存されているDTDに対してXMLファイルを検証するにはどうすればよいですか? XMLファイルにはDOCTYPE宣言がありません(または、オーバーライドする必要がある宣言がある場合があります)。 このスレッド を調べましたが、.NETを使用しているという事実に加えて、これが良い解決策であるとは思えません。

どんな入力でも大歓迎です!

24
Simon

理想的な世界では、 Validator を使用して検証できます。このようなもの:

SchemaFactory schemaFactory = SchemaFactory
    .newInstance(XMLConstants.XML_DTD_NS_URI);
Schema schema = schemaFactory.newSchema(new File(
    "xmlValidate.dtd"));
Validator validator = schema.newValidator();
validator.validate(new StreamSource("xmlValidate.xml"));

残念ながら、Sunの実装(少なくともJava 6)の時点では、DTDからスキーマインスタンスを作成するためのサポートは含まれていません。サードパーティの実装を追跡できる可能性があります。

他のメカニズムを使用して解析する前に、ドキュメントを変更してDTDを含めることをお勧めします。


transformer を使用して、DTD宣言を挿入できます。

TransformerFactory tf = TransformerFactory
    .newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(
    OutputKeys.DOCTYPE_SYSTEM, "xmlValidate.dtd");
transformer.transform(new StreamSource(
    "xmlValidate.xml"), new StreamResult(System.out));

...しかし、これは既存のDTD宣言を置き換えるものではないようです。


この StAX イベントリーダーは仕事をすることができます:

  public static class DTDReplacer extends
      EventReaderDelegate {

    private final XMLEvent dtd;
    private boolean sendDtd = false;

    public DTDReplacer(XMLEventReader reader, XMLEvent dtd) {
      super(reader);
      if (dtd.getEventType() != XMLEvent.DTD) {
        throw new IllegalArgumentException("" + dtd);
      }
      this.dtd = dtd;
    }

    @Override
    public XMLEvent nextEvent() throws XMLStreamException {
      if (sendDtd) {
        sendDtd = false;
        return dtd;
      }
      XMLEvent evt = super.nextEvent();
      if (evt.getEventType() == XMLEvent.START_DOCUMENT) {
        sendDtd = true;
      } else if (evt.getEventType() == XMLEvent.DTD) {
        // discard old DTD
        return super.nextEvent();
      }
      return evt;
    }

  }

ドキュメントの開始直後に特定のDTD宣言を送信し、古いドキュメントからすべてを破棄します。

デモの使用法:

XMLEventFactory eventFactory = XMLEventFactory.newInstance();
XMLEvent dtd = eventFactory
    .createDTD("<!DOCTYPE Employee SYSTEM \"xmlValidate.dtd\">");

XMLInputFactory inFactory = XMLInputFactory.newInstance();
XMLOutputFactory outFactory = XMLOutputFactory.newInstance();
XMLEventReader reader = inFactory
    .createXMLEventReader(new StreamSource(
        "xmlValidate.xml"));
reader = new DTDReplacer(reader, dtd);
XMLEventWriter writer = outFactory.createXMLEventWriter(System.out);
writer.add(reader);
writer.flush();

// TODO error and proper stream handling

XMLEventReaderは、検証を実行する他の変換メカニズムのソースを形成できることに注意してください。


そのオプションがある場合は、W3スキーマを使用して検証する方がはるかに簡単です。

26
McDowell

前述のものがうまくいくと確信しています。

ご協力ありがとうございます。DOCTYPEがまったく指定されていない場合はどうなりますか?その場合、EntityResolverは役に立ちませんか? – Simon、2009年7月8日6:34

@Bluegene:DOCTYPEがない場合、何を検証しますか? – J-16 SDiZ 2009年7月8日7:12

私自身のDTDに対して。受信したXMLが、送信者が指定したDTDだけでなく、DTDに準拠していることを確認したいだけです。 – Simon、2009年7月8日23:09

問題が作成者ではなくdtdに対して検証されることである場合は、doctypeの詳細と、xmlファイルに何が含まれている必要があるかを詳細に説明する明確なドキュメントがあることを確認する必要があります。

3
zachary

EntityResolver、チェックアウト この例 を実装する必要があります。

1
J-16 SDiZ