XML验证报错:元素'mappings'未声明,求问题排查方案
XML Schema验证报错:无法找到元素'mappings'的声明
我在进行XML验证时遇到了问题,以下是我的相关代码和内容:
待验证的XML内容
<mappings> <mapping> <protobufMessage>pb::Header</protobufMessage> <rosPackage>std_msgs</rosPackage> <rosMessage>Header</rosMessage> </mapping> </mappings>
用于验证的XML Schema
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" > <xs:element name="mappings"> <xs:complexType> <xs:sequence> <xs:element name="mapping" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="protobufMessage" type="xs:string"/> <xs:element name="rosPackage" type="xs:string"/> <xs:element name="rosMessage" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
错误信息
org.xml.sax.SAXParseException; cvc-elt.1: Cannot find the declaration of element 'mappings'. at [...]
验证用的Xtend代码
def private validate(InputStream is) { val parserF = DocumentBuilderFactory.newInstance val parser = parserF.newDocumentBuilder val document = parser.parse(is) val validatorF = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) val schemaSource = new StreamSource(new StringReader(schema)) // schema is a String member which contains the schema val valSchema = validatorF.newSchema(schemaSource) val validator = valSchema.newValidator validator.validate(new DOMSource(document)) }
问题分析
你遇到的这个错误核心原因是XML文档和Schema的命名空间处理不匹配,再加上默认的XML解析器没有启用命名空间感知,导致验证器找不到元素的声明:
- 你的Schema设置了
elementFormDefault="qualified",这要求所有元素都属于某个命名空间,但你的Schema没有声明targetNamespace,XML也没有指定任何命名空间,两边无法匹配。 - 默认的
DocumentBuilderFactory是不启用命名空间感知的,解析后的DOM文档不会正确处理元素的命名空间信息,进一步加剧了这个问题。
解决方案
方案1:给Schema添加目标命名空间,让XML关联它
首先修改Schema,添加targetNamespace和默认命名空间绑定:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/mappings" xmlns="http://example.com/mappings" elementFormDefault="qualified" > <xs:element name="mappings"> <!-- 其余内容保持不变 --> </xs:element> </xs:schema>
然后修改XML文档,添加对应的默认命名空间:
<mappings xmlns="http://example.com/mappings"> <mapping> <protobufMessage>pb::Header</protobufMessage> <rosPackage>std_msgs</rosPackage> <rosMessage>Header</rosMessage> </mapping> </mappings>
方案2:关闭Schema的限定模式,同时启用解析器的命名空间感知
如果你不需要使用命名空间,可以调整Schema的elementFormDefault为unqualified:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" > <!-- 其余内容保持不变 --> </xs:schema>
关键步骤:一定要给DocumentBuilderFactory启用命名空间感知,这是很多人容易忽略的点:
def private validate(InputStream is) { val parserF = DocumentBuilderFactory.newInstance // 启用命名空间感知,这是必须的 parserF.setNamespaceAware(true) val parser = parserF.newDocumentBuilder val document = parser.parse(is) val validatorF = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) val schemaSource = new StreamSource(new StringReader(schema)) val valSchema = validatorF.newSchema(schemaSource) val validator = valSchema.newValidator validator.validate(new DOMSource(document)) }
总结
两种方案都能解决问题,如果你需要在多Schema场景下区分元素,优先选方案1;如果只是简单的单Schema验证,方案2更简洁。但无论哪种方案,启用DocumentBuilderFactory的命名空间感知都是必不可少的——这大概率是你这次报错的直接原因。
内容的提问来源于stack exchange,提问作者kutschkem
相关产品推荐
相关产品推荐

