web-dev-qa-db-fra.com

Comment analyser un XML invalide (mauvais / mal formé)?

Actuellement, je travaille sur une fonctionnalité qui implique l'analyse XML que nous recevons d'un autre produit. J'ai décidé d'exécuter des tests sur certaines données réelles des clients, et il semble que l'autre produit autorise la saisie d'utilisateurs qui devraient être considérés comme non valides. Quoi qu'il en soit, je dois encore essayer de trouver un moyen de l'analyser. Nous utilisons javax.xml.parsers.DocumentBuilder Et j'obtiens une erreur d'entrée qui ressemble à ceci.

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

Comme vous pouvez le constater, la description contient ce qui semble être une balise non valide (<THIS-IS-PART-OF-DESCRIPTION>). Maintenant, cette balise de description est connue pour être une balise leaf et ne devrait pas contenir de balises imbriquées. Quoi qu'il en soit, c'est toujours un problème et génère une exception sur DocumentBuilder.parse(...)

Je sais que ce XML n'est pas valide, mais il est prévisible non valide. Des idées sur la façon d'analyser une telle entrée?

16
jvhashe

Ce "XML" est pire que invalide - c'est pas bien formé; voir Bien formé vs XML valide.

Une évaluation informelle de la prévisibilité des transgressions n'aide pas. Ces données textuelles ne sont pas XML. Aucun outil ou bibliothèque XML conforme ne peut vous aider à le traiter.

Options, les plus souhaitables en premier:

  1. Demandez au fournisseur de résoudre le problème de son côté. Exigez un XML bien formé. (Techniquement, la phrase XML ​​bien formé est redondante mais peut être utile pour l'accentuation. )
  2. Utilisez un analyseur de balisage tolérant pour nettoyer le problème avant d'analyser en XML:

  3. Traitez les données sous forme de texte manuellement à l'aide d'un éditeur de texte ou par programmation à l'aide de fonctions de caractères/chaînes. Faire cela par programme peut aller de délicat à impossible car ce qui semble souvent prévisible ne l'est pas - la violation des règles est rarement lié par des règles .

    • Pour les erreurs de caractères non valides , utilisez l'expression régulière pour supprimer/remplacer les caractères non valides:
      • 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, '')
    • Pour esperluette , utilisez l'expression régulière pour remplacer les correspondances par &amp;crédit: blhsin , demo

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

    Notez que les expressions régulières ci-dessus ne prendront pas en compte les commentaires ou les sections CDATA.

20
kjhughes

Un analyseur XML standard n'acceptera JAMAIS du XML non valide, de par sa conception.

Votre seule option est de prétraiter l'entrée pour supprimer le contenu "prévisible invalide", ou de l'envelopper dans CDATA, avant de l'analyser.

1
Jim Garrison

OMI, ces cas doivent être résolus en utilisant JSoup .

Ci-dessous une réponse pas vraiment à ce cas spécifique, mais trouvée ceci sur le web (merci à inuyasha82 sur Coderwall). Ce bit de code m'a inspiré pour un autre problème similaire en traitant des XML malformés, donc je le partage ici.

Veuillez ne pas modifier ce qui est ci-dessous, tel qu'il est sur le site Web d'origine.

Le format XML, nécessite d'être valide un élément racine unique déclaré dans le document. Ainsi, par exemple, un xml valide est:

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

Mais si vous avez un document comme:

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

Ceci sera considéré comme un XML mal formé, donc de nombreux analyseurs xml lèvent juste une exception ne se plaignant d'aucun élément racine. Etc.

Dans cet exemple, il existe une solution pour résoudre ce problème et analyser avec succès le fichier XML mal formé ci-dessus.

Fondamentalement, ce que nous allons faire est d'ajouter par programmation un élément racine.

Vous devez donc tout d'abord ouvrir la ressource qui contient votre xml "malformé" (c'est-à-dire un fichier):

File file = new File(pathtofile);

Ouvrez ensuite un FileInputStream:

FileInputStream fis = new FileInputStream(file);

Si nous essayons d'analyser ce flux avec une bibliothèque XML à ce stade, nous lèverons l'exception de document mal formé.

Nous créons maintenant une liste d'objets InputStream avec trois éléments:

Un élément ByteIputStream qui contient la chaîne: "" Notre FileInputStream Un ByteInputStream avec la chaîne: "" Le code est donc:

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

Maintenant, en utilisant un SequenceInputStream, nous créons un conteneur pour la liste créée ci-dessus:

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

Maintenant, nous pouvons utiliser n'importe quelle bibliothèque XML Parser, sur le cntr, et elle sera analysée sans aucun problème. (Vérifié avec la bibliothèque Stax);

1
Benj

La réponse acceptée est un bon conseil et contient des liens très utiles.

Je voudrais ajouter que cela, et beaucoupautres les cas de XML non bien formé et/ou invalide DTD peuvent être réparés en utilisant SGML, le sur-ensemble normalisé ISO de HTML et XML. Dans votre cas, ce qui fonctionne, c'est de déclarer le faux THIS-IS-PART-OF-DESCRIPTION élément en tant qu'élément vide SGML, puis utilisez par exemple. le programme osx (qui fait partie du package OpenSP/OpenJade SGML) pour le convertir en XML. Par exemple, si vous fournissez les éléments suivants à 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>

il produira un XML bien formé pour un traitement ultérieur avec les outils XML de votre choix.

Notez cependant que votre exemple d'extrait de code présente un autre problème dans le fait que les noms d'éléments commençant par les lettres xml ou XML ou Xml etc. sont réservés en XML et ne le seront pas. être acceptée par les analyseurs XML conformes.

1
imhotap