web-dev-qa-db-ja.com

無効な(不正な/整形式でない)XMLを解析する方法は?

現在、私は別の製品から受け取ったXMLの解析を含む機能に取り組んでいます。実際の顧客データに対していくつかのテストを実行することにしましたが、他の製品は無効と見なされるべきユーザーからの入力を許可しているようです。とにかく、私はまだそれを解析する方法を試してみなければなりません。 _javax.xml.parsers.DocumentBuilder_を使用していますが、入力時に次のようなエラーが表示されます。

_<xml>
  ...
  <description>Example:Description:<THIS-IS-PART-OF-DESCRIPTION></description>
  ...
</xml>
_

おわかりのように、説明にはその中に無効なタグのように見えるものがあります(_<THIS-IS-PART-OF-DESCRIPTION>_)。現在、この説明タグはリーフタグであることがわかっており、内部にネストされたタグを含めることはできません。とにかく、これはまだ問題であり、DocumentBuilder.parse(...)で例外を生成します

私はこれが無効なXMLであることを知っていますが、予想通り無効です。そのような入力を解析する方法に関するアイデアはありますか?

16
jvhashe

「XML」は無効よりも悪い–それは非整形式; Well Formed vs Valid XMLを参照してください。

違反の予測可能性の非公式の評価は役に立たない。そのテキストデータはXMLではありません。準拠するXMLツールまたはライブラリは、処理に役立ちません。

オプション、最も望ましい最初:

  1. プロバイダーに問題を解決してもらってください。 整形式XMLを要求します。 (技術的には整形式XMLというフレーズは冗長ですが、強調に役立つ場合があります。)
  2. トレラントマークアップパーサーを使用して XMLとして解析する前に問題をクリーンアップします。

  3. データをテキストとして処理しますテキストエディターを使用して手動で、または文字/文字列関数を使用してプログラムで処理します。これをプログラムで行うことは、トリッキーから不可能まで多岐にわたります予測可能と思われるものはそうではないので、-ルール違反はルールに拘束されることはほとんどありません

    • 無効な文字エラーの場合、regexを使用して無効な文字を削除/置換します:
      • PHP:preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $s);
      • Ruby:string.tr("^\u{0009}\u{000a}\u{000d}\u{0020}-\u{D7FF}\u{E000‌​}-\u{FFFD}", ' ')
      • JavaScript:inputStr.replace(/[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm, '')
    • アンパサンドの場合、正規表現を使用して一致を_&amp;_に置き換えます。 クレジット: blhsinデモ

      _&(?!(?:#\d+|#x[0-9a-f]+|\w+);)
      _

    上記の正規表現では、コメントやCDATAセクションは考慮されないことに注意してください。

20
kjhughes

標準のXMLパーサーは、設計上、無効なXMLを決して受け入れません。

唯一のオプションは、入力を前処理して「予測不可能な」コンテンツを削除するか、解析する前にCDATAでラップすることです。

1
Jim Garrison

IMOこれらのケースは JSoup を使用して解決する必要があります。

以下はこの特定のケースに対する実際の答えではありませんが、 ウェブ上のこれ (Coderwallのinuyasha82のおかげです)が見つかりました。このコードビットは、不正な形式のXMLを処理する際に別の同様の問題を引き起こしたので、ここで共有します。

元のウェブサイトと同じように、以下を編集しないでください。

XML形式では、ドキュメントで宣言された一意のルート要素が有効である必要があります。たとえば、有効なxmlは次のとおりです。

<root>
     <element>...</element>
     <element>...</element>
</root>

しかし、次のようなドキュメントがある場合:

<element>...</element>
<element>...</element>
<element>...</element>
<element>...</element>

これは不正なXMLと見なされるため、多くのxmlパーサーはルート要素がないことを訴える例外をスローします。等。

この例では、その問題を解決し、上記の不正なxmlを正常に解析する方法に関するソリューションがあります。

基本的に、プログラムでルート要素を追加します。

したがって、まず、「不正な形式の」xml(つまりファイル)を含むリソースを開く必要があります。

File file = new File(pathtofile);

次に、FileInputStreamを開きます。

FileInputStream fis = new FileInputStream(file);

その時点でこのストリームをXMLライブラリで解析しようとすると、不正な形式のドキュメント例外が発生します。

次に、3つの要素を持つInputStreamオブジェクトのリストを作成します。

ストリングを含むByteIputStream要素: "" Our FileInputStreamストリングを含むByteInputStream: ""したがって、コードは次のとおりです。

List<InputStream> streams = 
    Arrays.asList(
        new ByteArrayInputStream("<root>".getBytes()),
    fis,
    new ByteArrayInputStream("</root>".getBytes()));

次に、SequenceInputStreamを使用して、上記で作成したリストのコンテナーを作成します。

InputStream cntr = 
new SequenceInputStream(Collections.enumeration(str));

これで、cntrで任意のXMLパーサーライブラリを使用でき、問題なく解析されます。 (Staxライブラリで確認);

1
Benj

受け入れられた答えは良いアドバイスであり、非常に役立つリンクが含まれています。

これを追加したいのですが、 manyother 整形式および/またはDTD無効なXMLのケースは、ISO標準のスーパーセットであるSGMLを使用して修復できますHTMLおよびXML。あなたの場合、うまくいくのは偽のTHIS-IS-PART-OF-DESCRIPTION要素をSGMLの空要素として使用してから、たとえばosxプログラム(OpenSP/OpenJade SGMLパッケージの一部)をXMLに変換します。たとえば、osxに次を指定すると

<!DOCTYPE xml [
  <!ELEMENT xml - - ANY>
  <!ELEMENT description - - ANY>
  <!ELEMENT THIS-IS-PART-OF-DESCRIPTION -  - EMPTY>
]>
<xml>
  <description>blah blah
    <THIS-IS-PART-OF-DESCRIPTION>
  </description>
</xml>

適切な形式のXMLを出力して、選択したXMLツールでさらに処理します。

ただし、サンプルスニペットには、xmlまたはXMLまたはXmlなどの文字で始まる要素名がXMLで予約されているため、別の問題があることに注意してください。準拠するXMLパーサーによって受け入れられます。

1
imhotap