XML Schema验证报错:无法找到CC:companySendType元素声明
问题场景
使用Java代码结合companySendType.xsd(包含对companyType.xsd的引用)验证XML时,出现错误:
Cannot find the declaration of element 'CC:companySendType'
相关文件及代码如下:
1. companySendType.xsd 内容
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:CC="http://test.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://test.com" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:include schemaLocation="companyType.xsd"/> <xs:element name="companySendType" > <xs:complexType> ... </xs:complexType> </xs:element> </xs:schema>
2. 原Java验证代码
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = sf.newSchema(new Source[]{ new StreamSource(ClassLoader.getSystemClassLoader().getResourceAsStream("companyType.xsd")), new StreamSource(ClassLoader.getSystemClassLoader().getResourceAsStream("companySendType.xsd")) }); Validator validator = schema.newValidator(); StringReader stringReader = new StringReader(xmlToValidate); StreamSource streamSource = new StreamSource(stringReader); validator.validate(streamSource);
3. 待验证XML
<?xml version="1.0" encoding="UTF-8"?> <CC:companySendType version="1.0" xsi:schemaLocation="http://test.com companySendTypev1.18.xsd" xmlns:CC="http://test.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> </CC:companySendType>
报错原因
XSD加载时未设置SystemId,导致include依赖无法解析:
直接使用getResourceAsStream获取XSD流,没有关联文件的实际路径。解析companySendType.xsd中的<xs:include schemaLocation="companyType.xsd"/>时,解析器无法定位到依赖的companyType.xsd,导致companySendType元素的定义未被完整加载。XML的schemaLocation与实际加载的XSD文件名不匹配:
XML中指定的schema文件是companySendTypev1.18.xsd,但Java代码加载的是companySendType.xsd,虽然Java验证会忽略XML中的schemaLocation直接使用指定的Schema,但文件名不一致可能引发潜在问题。
解决方法
方法1:为StreamSource设置SystemId,确保include能找到依赖文件
修改Java代码,通过资源URL获取流并设置SystemId,让解析器能正确定位依赖XSD:
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // 获取资源URL,用于设置SystemId URL companyTypeUrl = ClassLoader.getSystemClassLoader().getResource("companyType.xsd"); URL companySendTypeUrl = ClassLoader.getSystemClassLoader().getResource("companySendType.xsd"); Schema schema = sf.newSchema(new Source[]{ new StreamSource(companyTypeUrl.openStream(), companyTypeUrl.toString()), new StreamSource(companySendTypeUrl.openStream(), companySendTypeUrl.toString()) }); Validator validator = schema.newValidator(); StringReader stringReader = new StringReader(xmlToValidate); StreamSource streamSource = new StreamSource(stringReader); validator.validate(streamSource);
或者更简洁的方式(因为companySendType.xsd已包含对companyType.xsd的引用,只需加载主XSD并设置SystemId):
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); URL sendTypeUrl = ClassLoader.getSystemClassLoader().getResource("companySendType.xsd"); Schema schema = sf.newSchema(new StreamSource(sendTypeUrl.openStream(), sendTypeUrl.toString())); Validator validator = schema.newValidator(); StringReader stringReader = new StringReader(xmlToValidate); StreamSource streamSource = new StreamSource(stringReader); validator.validate(streamSource);
方法2:统一XML与代码中的XSD文件名
修改XML的xsi:schemaLocation,使其与实际加载的XSD文件名一致:
<?xml version="1.0" encoding="UTF-8"?> <CC:companySendType version="1.0" xsi:schemaLocation="http://test.com companySendType.xsd" xmlns:CC="http://test.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> </CC:companySendType>
内容的提问来源于stack exchange,提问作者dssof

