如何解决SAXParseException:XML文档结构必须在同一实体中首尾匹配
XML解析问题:获取字段值时遇到SAXParseException错误
问题详情
我在解析XML获取字段值时遇到异常,XML示例如下:
<?xml version="1.0" encoding="UTF-8"?><Document xmlns="urn:iso:std:iso:20022:tech:xsd:notificationName"> <Ntfctn> <MsgHdr> <MsgId>47e22e35-6866-46f0-bc5d-8b5bb6afaba7</MsgId> <CreDt>2023-07-03T20:41:20Z</CreDt> <Fr>66666666-6666-4666-8666-666666666666</Fr> <To>93216692-7432-444d-88a1-18297159a92a</To> <OprId>4e8cf5f6-c6e1-4314-b043-65dfe13ab2fa</OprId> </MsgHdr> <OprInfAndSts> <OprInf> <DCXchgOprInf> <XchgOprAmt> <TtlAmt Ccy="RUB">147.71</TtlAmt> </XchgOprAmt> <DgtlCcyTrfData> <DCBuyr> <Wllt> <Id>93216692-7432-444d-88a1-18297159a92a</Id> <Bal> <TtlAmt Ccy="RUB">13122.60</TtlAmt> </Bal> </Wllt> </DCBuyr> </DgtlCcyTrfData> <SttlmDtTm>2023-07-03T20:41:20Z</SttlmDtTm> </DCXchgOprInf> </OprInf> </OprInfAndSts> </Ntfctn> </Document>
我编写的字段获取方法:
public String getFieldValue(String xml, String tagName, String tagValue) { xml = xml.trim().replaceFirst("<?","<"); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); Document parse = documentBuilderFactory.newDocumentBuilder().parse(byteArrayInputStream); NodeList nodeList = parse.getElementsByTagName(tagName); Node item = nodeList.item(0); return item.getTextContent(); }
此前遇到"content is not allowed in prolog"错误,添加trim()和replaceFirst()后解决,但现在调用方法时触发SAXParseException,提示"XML document structures must start and end within the same entity",不知道如何修复。
修复方案
1. 移除错误的XML声明修改操作
你的replaceFirst("<?","<")直接破坏了XML声明的合法性,把<?xml ...?>改成了<xml ...?>,导致解析器无法识别完整的文档结构,这是当前错误的核心原因。之前的prolog错误大概率是XML开头存在隐藏的UTF-8 BOM字符,不该用粗暴替换的方式解决。
2. 正确处理开头的隐藏字符
替换掉错误的replaceFirst,改用安全方式过滤可能的BOM和空白:
if (xml.startsWith("\uFEFF")) { xml = xml.substring(1); } xml = xml.trim();
3. 处理XML命名空间
你的XML带有命名空间urn:iso:std:iso:20022:tech:xsd:notificationName,默认的getElementsByTagName无法识别带命名空间的元素,需要启用命名空间支持并使用getElementsByTagNameNS:
public String getFieldValue(String xml, String namespaceUri, String tagName) { // 处理BOM和开头空白 if (xml.startsWith("\uFEFF")) { xml = xml.substring(1); } xml = xml.trim(); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); // 启用命名空间支持 documentBuilderFactory.setNamespaceAware(true); try { Document parse = documentBuilderFactory.newDocumentBuilder().parse(byteArrayInputStream); NodeList nodeList = parse.getElementsByTagNameNS(namespaceUri, tagName); if (nodeList.getLength() > 0) { return nodeList.item(0).getTextContent(); } return null; } catch (Exception e) { e.printStackTrace(); return null; } }
调用时传入命名空间参数:
String oprId = getFieldValue(xmlContent, "urn:iso:std:iso:20022:tech:xsd:notificationName", "OprId");
4. 额外注意事项
- 不要手动修改XML的结构或声明,极易引入语法错误
- 解析带命名空间的XML时,必须启用命名空间支持
- 解析过程中捕获异常并打印堆栈信息,便于排查问题
内容的提问来源于stack exchange,提问作者Ruslan Fazylyanov
相关产品推荐
相关产品推荐

