在GAE上解析完全有效的XML时出现“Content is not allowed in prolog”错误。

177

在过去的48个小时里,我一直在努力解决这个极其恼人的错误,所以我想在我将笔记本电脑扔出窗户之前,在这里试着来问问。

我正在尝试解析我从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 看起来与我预期的完全一致和正确,但是出现以下异常无法解析响应:

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编码字符等问题。我通过字节方式在数组中逐字节查看是否存在字节顺序标记或类似的内容,但什么都没有发现。这个XML文件通过了我能够施加的所有验证测试。更奇怪的是,如果我使用基于Saxon的解析器,它也会出现相同的问题——但只有在GAE上,而在我的本地环境中一切正常。
这使得当我只能在完全正常的环境上运行调试器时,要追踪代码中的问题变得非常困难(我还没有找到任何远程调试GAE的好方法)。尽管如此,我尝试了无数种方法,包括:
- 使用和不使用XML声明 - 使用和不使用换行符 - 在XML声明中使用和不使用“encoding=”属性 - 两种换行样式 - 在HTTP流中使用和不使用分块信息
我已经尝试了其中大部分的组合,但仍然没有发现问题。我已经束手无策了。有没有人见过类似的问题,并能帮我找到一些线索呢?
谢谢!

5
@Raedwald,我不认为我的问题是重复的,因为我的问题比那个问题早一年发表 :) - Adrian Petrescu
另一个问题更有用作为规范问题,因为它更加通用。 - Raedwald
@AdrianPetrescu 请查看此 MSE 答案:http://meta.stackexchange.com/a/147651/170084 - Raedwald
1
这应该是一个关于如何在SO上提问的示例,阅读它让我获得了作为开发者进行调试的各种见解(感谢原帖作者)。 - Sudip Bhandari
显示剩余2条评论
16个回答

177

您的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]+)<","<");

2
谢谢!这也帮了我大忙。xml.trim().replaceFirst("^([\W]+)<","<"); - stackoverflow
2
有人可以把这个答案标为已采纳吗?直接解决了我的问题。我正在解析一个以“Message: <?xml version...."开头的消息。问题出在xml之前的文本上。谢谢 :) - Ric Jafe
这解决了我在一个网站的feed xml中遇到的问题。但是对于其他URL,它会出现问题,而之前解析器没有任何问题。我无法确定正则表达式"^([\W]+)<"确切的作用。我正在从输入流中获取XML。请解释一下这个正则表达式的工作原理。 - codeMan
@codeMan 正则表达式将所有开头的空格和开头的 < 替换为 < - Romain Hippeau
@ Romain 我们可以使用Notepad++更改编码。那样行吗? - Vishnu T S
显示剩余13条评论

17

在使用Notepad++检查XML文件并保存该文件时,我遇到了问题,尽管我有顶部的utf-8 xml标签<?xml version="1.0" encoding="utf-8"?>

通过在Notepad++中使用编码(Tab) > 编码为UTF-8:选定(之前是编码为UTF-8-BOM),问题得到解决。


我曾经遇到过类似的问题。在我的情况下,XML头部没有编码属性。Notepad++默认使用UTF-8编码。一旦我将Notepad++编码切换为ANSI,问题就解决了。 - lafual
1
通过Vim从工作目录中的所有XML文件中删除BOM:vim -c“:bufdo set nobomb | update”-c“q”*.xml - Fofola

11

该错误消息通常是由开始元素中无效的XML内容引起的。例如,在XML元素开头有额外的小圆点“。”。

在“<?xml...”之前的任何字符都会导致上述“org.xml.sax.SAXParseException: Content is not allowed in prolog”错误消息。

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

要修复它,只需删除“<?xml“之前的所有奇怪字符即可。

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


3
你应该提到你参考了哪里,即http://www.mkyong.com/java/sax-error-content-is-not-allowed-in-prolog/。 - arulraj.net

7

今天我遇到了相同的错误信息。 解决方法是将文档从UTF-8带BOM改为UTF-8无BOM。


我遇到了同样的问题。更改文件格式解决了这个问题。谢谢! - code_fish
真是太棒了,你是个冠军!我从来没想到过这个! - Kadaj

6

我遇到了同样的问题。在我的情况下,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

3
在我的 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在上面指出的那样,编码需要匹配。


2
去掉XML声明解决了这个问题。
<?xml version='1.0' encoding='utf-8'?>

2

未预料的原因:文件路径中的#字符

由于某些内部错误,如果您提供的文件名为 C:\Data\#22\file.xml,即使文件内容本身完全正确,也会出现错误提示 不允许在 prolog 中存在内容

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

如何检查:如果您将文件移动到没有特殊字符的路径中,错误提示消失,则是由于此问题导致的。

最初的回答


1
花了我两天时间才意识到这是问题所在。问题是由Tomcat服务正在运行的Windows用户名称引起的。用户名包含一个“#”字符,因此用户配置文件路径也包含此字符.... - schlomm

1

为了符合“删除所有在<?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);
        }
    }

就我所见,我看到的字节是(十进制):239、187、191。


1
我在我的xml文件中遇到了“内容不允许出现在prolog中”的相同问题。
解决方案
最初我的根文件夹是 '# Filename'。
当我删除第一个字符'#'时,错误得到了解决。
无需删除#filename... 可以尝试以下方法…
不要将File或URL对象传递给unmarshaller方法,而是使用FileInputStream。
File myFile = new File("........");
Object obj = unmarshaller.unmarshal(new FileInputStream(myFile));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接