在GAE上解析完全有效的XML时,“序言中不允许内容”


109

在过去的48个小时里,我一直对这个绝对令人毛骨悚然的bug感到震惊,所以我想我最终会把毛巾扔掉,尝试在这里问一下,然后再将笔记本电脑扔出窗户。

我正在尝试从对AWS SimpleDB的调用中解析响应XML。响应恢复正常。例如,它可能看起来像:

<?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>

我将此XML传递给解析器

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

并打电话eventReader.nextEvent();多次以获得我想要的数据。

这是奇怪的部分-它在本地服务器中很好用。我解析了响应,每个人都很高兴。问题是,当我将代码部署到Google App Engine时,传出请求仍然有效,并且响应XML对我来说似乎100%相同且正确,但是响应无法解析,但出现以下异常:

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)

我有两次,三次,四次检查此XML中的“不可见字符”或非UTF8编码字符,等等。我在数组中逐字节查看了字节顺序标记或类似性质的东西。没有; 它通过了我可能会提出的所有验证测试。更奇怪的是,如果我也使用基于Saxon的解析器,则会发生这种情况-但仅在GAE上,它在我的本地环境中始终可以正常工作。

当我只能在运行良好的环境中运行调试器时,很难找到问题的代码(我还没有找到在GAE上进行远程调试的任何好方法)。尽管如此,使用我拥有的原始方法,我已经尝试了上百万种方法,包括:

  • 有和没有序言的XML
  • 有无换行符
  • 在序言中是否包含“ encoding =“属性
  • 两种换行样式
  • HTTP流中是否存在分块信息

而且我已经尝试了多种方式中的大多数方式,在这些方式中它们会相互作用-没有任何作用!我机智的尽头。有没有人看到过这样的问题,希望可以对此有所启发?

谢谢!


我们可能需要看更多代码。另一种可能性是,在GAE上它不会在本地被分块。在将代码传递给解析器之前,如何处理代码?
罗曼·希波

我也考虑了分块的可能性,但是事实并非如此,因为解析器抛出的错误消息在那里包含整个XML(粘贴在上面)。完整的修改后的SDK代码可在github.com/AdrianP/aws-sdk-for-java中找到(查看最新提交),但那里有很多代码。我将尝试尽快创建较小的可重现样本,尽管即使那样也很难。这是一个非常复杂的软件...不过,感谢您的反馈!:)
Adrian Petrescu 2010年


@Raedwald,我不认为这是重复的问题,因为我的问题早于那个问题发布了一年:)
Adrian Petrescu 2014年

1
这应该是一个示例,说明如何在SO上提出问题,通读它使我对如何以开发人员的身份进行调试有了很多见解(感谢OP)
Sudip Bhandari

Answers:


129

XML和XSD(或DTD)中的编码不同。
XML文件头: <?xml version='1.0' encoding='utf-8'?>
XSD文件头:<?xml version='1.0' encoding='utf-16'?>

导致这种情况的另一种可能的情况是,在XML文档类型声明之前发生了任何事情。即您可能在缓冲区中有以下内容:

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

甚至是空格或特殊字符。

缓冲区中可能有一些特殊的字符,称为字节顺序标记。在将缓冲区传递给解析器之前,请执行此操作...

String xml = "<?xml ...";
xml = xml.trim().replaceFirst("^([\\W]+)<","<");

嗨,罗曼,谢谢您的回复!我已经多次检查了序言之前缓冲区中的任何内容(包括隐藏字符),但没有任何其他内容。但是,出于好奇,我将尝试切换到utf-16编码,您从哪里获得XSD使用UTF-16的信息?
阿德里安·彼得雷斯库

@Adrian Petrescu对不起,这些只是示例如果您使用的是DTD或XSD,请确保它们与XML匹配。在解析XML之前,请先将其捕获为字符串并用'|'包围 并将其打印到控制台。这将告诉您是否要传递一些额外的字符。
罗曼·希波

嗯,我知道了:)很遗憾,我尝试过了,在这种情况下似乎并非如此。不管怎么说,还是要谢谢你!
阿德里安·彼得雷斯库

1
谢谢!这也救了我。xml.trim()。replaceFirst(“ ^([\\ W] +)<”,“ <”);
stackoverflow 2013年

2
有人请将此作为可接受的答案。立即解决我的问题。我正在解析以“ Message:<?xml version ....”开头的Message,问题是xml位之前的文本。谢谢:)
Ric Jafe

8

此错误消息始终是由开始元素中的无效XML内容引起的。例如,多余的小点“。” 在XML元素的开头。

<?xml….” 之前的任何字符都将导致上述“ org.xml.sax.SAXParseException:序言中不允许内容 ”错误消息。

一个小点“ 之前“<?xml….

要解决此问题,只需删除“<?xml“。之前的所有那些奇怪的字符。

参考:http : //www.mkyong.com/java/sax-error-content-is-not-allowed-in-prolog/



5

我面临着同样的问题。就我而言,XML文件是从c#程序生成的,并被馈送到AS400中进行进一步处理。经过一番分析后,我确定在生成XML文件时正在使用UTF8编码,而javac(在AS400中)使用的是“无BOM的UTF8”。因此,不得不编写类似于下面提到的额外代码:

//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

5

我在notepad ++中检查xml文件并保存该文件时遇到了问题,尽管我将utf-8 xml顶部标记为 <?xml version="1.0" encoding="utf-8"?>

通过将文件保存在notpad ++中并使用Encoding(Tab)> UTF-8中的Encode:selected(在UTF-8-BOM中为Encode)来解决


3

删除xml声明解决了它

<?xml version='1.0' encoding='utf-8'?>

2

在我的xml文件中,标题看起来像这样:

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

在一个测试文件中,我正在读取文件字节并以UTF-8格式解码数据(未意识到该文件的标头是utf-16)以创建字符串。

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

当我尝试将此字符串反序列化为对象时,我看到了相同的错误:

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

当我将第二行更新为

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

我能够反序列化该对象。因此,正如Romain上文所述,编码需要匹配。


1

我在xml文件中遇到了相同的问题,即“序言中不允许内容”。

最初,我的根文件夹是' #Filename '。

当我删除第一个字符“#”时,错误得到解决。

无需删除#filename ...以这种方式尝试。

不要将File或URL对象传递给unmarshaller方法,而应使用FileInputStream。

File myFile = new File("........");
Object obj = unmarshaller.unmarshal(new FileInputStream(myFile));

1

意外的原因:#文件路径中的字符

由于某些内部错误,如果文件内容本身是100%正确,但您提供的文件名为,则错误也将出现在“序言中不允许出现内容”的错误C:\Data\#22\file.xml

这也可能适用于其他特殊字符。

如何检查:如果将文件移到没有特殊字符的路径中并且错误消失了,那么就是这个问题。


1

我今天也收到了同样的错误消息。解决方案是将文档从带有BOM的UTF-8更改为不带有BOM的UTF-8


我遇到过同样的问题。更改文件格式解决了该问题。谢谢!
code_fish

0

我有一个制表符而不是空格。替换选项卡'\ t'解决了该问题。

将整个文档剪切并粘贴到Notepad ++之类的编辑器中,并显示所有字符。


0

在我遇到的问题中,解决方案是用HTML等效项替换德国变音符号(äöü)...


0

以下是“ org.xml.sax.SAXParseException:序言中不允许内容”异常的原因。

  1. 首先检查schema.xsd和file.xml的文件路径。
  2. XML和XSD(或DTD)中的编码应该相同。
    XML文件头: <?xml version='1.0' encoding='utf-8'?>
    XSD文件头:<?xml version='1.0' encoding='utf-8'?>
  3. 如果XML文档类型声明之前有任何内容,即: hello<?xml version='1.0' encoding='utf-16'?>

0

本着“只删除<?xml之前的所有那些奇怪的字符”的精神,这是我的Java代码,该代码与通过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,我看到的字节是(十进制):239、187、191。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.