"Le contenu n'est pas autorisé dans le prologue" lors de l'analyse d'un XML parfaitement valide sur GAE

109

Je me suis cogné la tête contre ce bug absolument exaspérant pendant les 48 dernières heures, alors j'ai pensé que je jetterais enfin l'éponge et essayerais de demander ici avant de jeter mon ordinateur portable par la fenêtre.

J'essaie d'analyser le XML de réponse d'un appel que j'ai passé à AWS SimpleDB. La réponse revient très bien sur le fil; par exemple, cela peut ressembler à:

<?xml version="1.0" encoding="utf-8"?> 
<ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
    <ListDomainsResult>
        <DomainName>Audio</DomainName>
        <DomainName>Course</DomainName>
        <DomainName>DocumentContents</DomainName>
        <DomainName>LectureSet</DomainName>
        <DomainName>MetaData</DomainName>
        <DomainName>Professors</DomainName>
        <DomainName>Tag</DomainName>
    </ListDomainsResult>
    <ResponseMetadata>
        <RequestId>42330b4a-e134-6aec-e62a-5869ac2b4575</RequestId>
        <BoxUsage>0.0000071759</BoxUsage>
    </ResponseMetadata>
</ListDomainsResponse>

Je passe ce XML à un analyseur avec

XMLEventReader eventReader = xmlInputFactory.createXMLEventReader(response.getContent());

et appelez plusieurs eventReader.nextEvent();fois pour obtenir les données que je veux.

Voici la partie bizarre - cela fonctionne très bien à l'intérieur du serveur local. La réponse arrive, je l'analyse, tout le monde est content. Le problème est que lorsque je déploie le code sur Google App Engine, la requête sortante fonctionne toujours et le XML de réponse me semble 100% identique et correct, mais la réponse ne parvient pas à être analysée à l'exception suivante:

com.amazonaws.http.HttpClient handleResponse: Unable to unmarshall response (ParseError at [row,col]:[1,1]
Message: Content is not allowed in prolog.): <?xml version="1.0" encoding="utf-8"?> 
<ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/"><ListDomainsResult><DomainName>Audio</DomainName><DomainName>Course</DomainName><DomainName>DocumentContents</DomainName><DomainName>LectureSet</DomainName><DomainName>MetaData</DomainName><DomainName>Professors</DomainName><DomainName>Tag</DomainName></ListDomainsResult><ResponseMetadata><RequestId>42330b4a-e134-6aec-e62a-5869ac2b4575</RequestId><BoxUsage>0.0000071759</BoxUsage></ResponseMetadata></ListDomainsResponse>
javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,1]
Message: Content is not allowed in prolog.
    at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(Unknown Source)
    at com.sun.xml.internal.stream.XMLEventReaderImpl.nextEvent(Unknown Source)
    at com.amazonaws.transform.StaxUnmarshallerContext.nextEvent(StaxUnmarshallerContext.java:153)
    ... (rest of lines omitted)

J'ai vérifié double, triple, quadruple ce XML pour les «caractères invisibles» ou les caractères codés non UTF8, etc. Je l'ai regardé octet par octet dans un tableau pour les marques d'ordre d'octet ou quelque chose de cette nature. Rien; il passe tous les tests de validation que je pourrais lui lancer. Encore plus étrange, cela arrive si j'utilise également un analyseur basé sur Saxon - mais UNIQUEMENT sur GAE, cela fonctionne toujours bien dans mon environnement local.

Il est très difficile de suivre le code pour les problèmes lorsque je ne peux exécuter le débogueur que sur un environnement qui fonctionne parfaitement (je n'ai trouvé aucun bon moyen de déboguer à distance sur GAE). Néanmoins, en utilisant les moyens primitifs dont je dispose, j'ai essayé un million d'approches, notamment:

  • XML avec et sans le prologue
  • Avec et sans nouvelles lignes
  • Avec et sans l'attribut "encoding =" dans le prologue
  • Les deux styles de nouvelle ligne
  • Avec et sans les informations de segmentation présentes dans le flux HTTP

Et j'ai essayé la plupart d'entre eux dans de multiples combinaisons où il était logique qu'ils interagissent - rien! Je suis à bout de souffle. Quelqu'un a-t-il déjà vu un problème comme celui-ci qui, espérons-le, peut éclairer le sujet?

Merci!

Adrian Petrescu
la source
Nous allons probablement avoir besoin de plus de code. Une autre possibilité est que localement, il ne soit pas fragmenté alors qu'il l'est sur GAE. Comment gérez-vous le code avant de le transmettre à l'analyseur?
Romain Hippeau
J'ai également envisagé la possibilité de segmentation, mais cela ne semble pas être le cas puisque le message d'erreur que l'analyseur envoie contient tout le XML (il est collé ci-dessus). L'ensemble du code SDK modifié peut être trouvé sur github.com/AdrianP/aws-sdk-for-java (regardez les commits les plus récents) mais il y a BEAUCOUP de code. J'essaierai bientôt de créer un échantillon reproductible plus petit, même si cela sera difficile. C'est un gros logiciel compliqué ... Merci pour vos commentaires! :)
Adrian Petrescu
@Raedwald, je ne pense pas que ce soit ma question qui soit le double, puisque ma question a été postée un an plus tôt que celle-là :)
Adrian Petrescu
1
Cela devrait être un exemple de la façon dont une question devrait être posée sur SO, la lecture m'a donné diverses idées sur la façon de déboguer en tant que développeur (merci OP)
Sudip Bhandari

Réponses:

129

Le codage dans votre XML et XSD (ou DTD) est différent.
En-tête de fichier XML: en- <?xml version='1.0' encoding='utf-8'?>
tête de fichier XSD:<?xml version='1.0' encoding='utf-16'?>

Un autre scénario possible qui provoque cela est lorsque quelque chose vient avant la déclaration de type de document XML. c'est-à-dire que vous pourriez avoir quelque chose comme ça dans le tampon:

helloworld<?xml version="1.0" encoding="utf-8"?>  

ou même un espace ou un caractère spécial.

Il existe des caractères spéciaux appelés marqueurs d'ordre des octets qui pourraient se trouver dans le tampon. Avant de passer le tampon à l'analyseur, faites ceci ...

String xml = "<?xml ...";
xml = xml.trim().replaceFirst("^([\\W]+)<","<");
Romain Hippeau
la source
Salut Romain, merci pour la réponse! J'ai vérifié plusieurs fois deux fois et trois fois tout ce qui se trouvait dans le tampon avant le prologue (y compris les caractères cachés), mais il n'y a tout simplement rien d'autre. Je vais toutefois essayer de passer à l'encodage utf-16 - par curiosité, où avez-vous obtenu les informations selon lesquelles le XSD utilise UTF-16?
Adrian Petrescu
@Adrian Petrescu Désolé, ce ne sont que des exemples. Si vous utilisez des DTD ou des XSD, assurez-vous qu'ils correspondent à votre XML. Avant d'analyser le XML, capturez-le dans une chaîne et entourez-le de '|' et imprimez-le sur la console. Cela vous dira si vous passez des caractères supplémentaires.
Romain Hippeau
Ah, je vois :) Malheureusement, je l'ai essayé et cela ne semble pas être le cas dans cette situation. Merci quand même!
Adrian Petrescu
1
Merci! Cela m'a sauvé aussi. xml.trim (). replaceFirst ("^ ([\\ W] +) <", "<");
stackoverflow
2
Quelqu'un s'il vous plaît en faire la réponse acceptée. J'ai résolu mon problème tout de suite. J'analysais un message commençant par "Message: <? Xml version ...." Le problème était le texte avant le bit xml. Merci :)
Ric Jafe
8

Ce message d'erreur est toujours provoqué par le contenu XML non valide dans l'élément de début. Par exemple, un petit point supplémentaire "." au début de l'élément XML.

Tout caractère précédant le " <?xml…." provoquera le message d'erreur " org.xml.sax.SAXParseException: le contenu n'est pas autorisé dans le prologue ".

Un petit point » . " avant le“<?xml….

Pour résoudre ce problème, supprimez simplement tous ces caractères étranges avant le “<?xml“.

Réf: http://www.mkyong.com/java/sax-error-content-is-not-allowed-in-prolog/

Sunmit Girme
la source
3
Vous devriez mentionner où vous avez fait référence à mkyong.com/java/sax-error-content-is-not-allowed-in-prolog
arulraj.net
5

J'étais confronté au même problème. Dans mon cas, les fichiers XML ont été générés à partir du programme c # et alimentés dans AS400 pour un traitement ultérieur. Après quelques analyses, j'ai identifié que j'utilisais le codage UTF8 lors de la génération de fichiers XML alors que javac (dans AS400) utilise "UTF8 sans BOM". Donc, j'ai dû écrire un code supplémentaire similaire à celui mentionné ci-dessous:

//create encoding with no BOM
Encoding outputEnc = new UTF8Encoding(false); 
//open file with encoding
TextWriter file = new StreamWriter(filePath, false, outputEnc);           

file.Write(doc.InnerXml);
file.Flush();
file.Close(); // save and close it
Saturne CAU
la source
5

J'ai eu un problème lors de l'inspection du fichier xml dans notepad ++ et de l'enregistrement du fichier, même si j'avais la balise xml utf-8 supérieure comme <?xml version="1.0" encoding="utf-8"?>

Obtenu corrigé en enregistrant le fichier dans notpad ++ avec Encoding (Tab)> Encode en UTF-8: sélectionné (était Encode en UTF-8-BOM)

techloris_109
la source
3

La suppression de la déclaration xml l'a résolu

<?xml version='1.0' encoding='utf-8'?>
FOO
la source
2

Dans mon fichier xml, l'en-tête ressemblait à ceci:

<?xml version="1.0" encoding="utf-16"? />

Dans un fichier de test, je lisais les octets du fichier et décodais les données en UTF-8 (ne réalisant pas que l'en-tête de ce fichier était utf-16) pour créer une chaîne.

byte[] data = Files.readAllBytes(Paths.get(path));
String dataString = new String(data, "UTF-8");

Lorsque j'ai essayé de désérialiser cette chaîne en un objet, je voyais la même erreur:

javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,1]
Message: Content is not allowed in prolog.

Quand j'ai mis à jour la deuxième ligne en

String dataString = new String(data, "UTF-16");

J'ai pu désérialiser l'objet très bien. Ainsi, comme Romain l'avait noté plus haut, les encodages doivent correspondre.

dfritch
la source
1

J'étais confronté au même problème appelé "Le contenu n'est pas autorisé dans le prologue" dans mon fichier xml.

Solution

Au départ, mon dossier racine était «# Filename ».

Lorsque j'ai supprimé le premier caractère «#», l'erreur a été résolue.

Pas besoin de supprimer le #filename ... Essayez de cette manière ..

Au lieu de passer un objet File ou URL à la méthode unmarshaller, utilisez un FileInputStream.

File myFile = new File("........");
Object obj = unmarshaller.unmarshal(new FileInputStream(myFile));
Ravi Kiran
la source
1

Raison inattendue: #caractère dans le chemin du fichier

En raison d'un bug interne, l'erreur Le contenu n'est pas autorisé dans le prologue apparaît également si le contenu du fichier lui-même est correct à 100% mais que vous fournissez le nom du fichier comme C:\Data\#22\file.xml.

Cela peut également s'appliquer à d'autres caractères spéciaux.

Comment vérifier: Si vous déplacez votre fichier dans un chemin sans caractères spéciaux et que l'erreur disparaît, c'était le problème.

miroxlav
la source
1

J'ai attrapé le même message d'erreur aujourd'hui. La solution était de changer le document de UTF-8 avec BOM à UTF-8 sans BOM

matjung
la source
J'ai eu le même problème. La modification du format de fichier a résolu le problème. Merci!
code_fish
0

J'avais un caractère de tabulation au lieu d'espaces. Le remplacement de l'onglet '\ t' a résolu le problème.

Coupez et collez tout le document dans un éditeur comme Notepad ++ et affichez tous les caractères.

SoloPilot
la source
0

Dans mon exemple du problème, la solution était de remplacer les trémas allemands (äöü) par leurs équivalents HTML ...

MBaas
la source
0

ci-dessous sont la cause au-dessus de l'exception «org.xml.sax.SAXParseException: le contenu n'est pas autorisé dans le prologue».

  1. Vérifiez d'abord le chemin du fichier schema.xsd et file.xml.
  2. Le codage dans votre XML et XSD (ou DTD) doit être le même.
    En-tête de fichier XML: en- <?xml version='1.0' encoding='utf-8'?>
    tête de fichier XSD:<?xml version='1.0' encoding='utf-8'?>
  3. si quelque chose vient avant la déclaration de type de document XML.ie: hello<?xml version='1.0' encoding='utf-16'?>
Avinash Dubey
la source
0

Dans l'esprit de "supprimer simplement tous ces caractères étranges avant le <? Xml", voici mon code Java, qui fonctionne bien avec une entrée via un BufferedReader:

    BufferedReader test = new BufferedReader(new InputStreamReader(fisTest));
    test.mark(4);
    while (true) {
        int earlyChar = test.read();
        System.out.println(earlyChar);
        if (earlyChar == 60) {
            test.reset();
            break;
        } else {
            test.mark(4);
        }
    }

FWIW, les octets que je voyais sont (en décimal): 239, 187, 191.

Tamias
la source