SAX解析器不跟随引用:HL7消息XSD跨文件解析问题咨询
解决SAX解析HL7 XSD时不跟随外部引用的问题
我之前也踩过这个坑——SAX解析器默认不会自动处理XSD里的外部引用(比如<xs:include>或<xs:import>),得手动配置或者调整解析逻辑才行。结合你拆分HL7消息和段定义的场景,给你几个可行的解决方案:
1. 自定义EntityResolver来处理外部文件引用
SAX解析器默认依赖系统的实体解析器,很可能找不到你拆分出去的段定义XSD文件。你可以写一个自定义的EntityResolver,手动指定外部XSD的查找路径:
import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import java.io.File; import java.io.FileInputStream; import java.io.IOException; class HL7XSDEntityResolver implements EntityResolver { private final String xsdBaseDir; public HL7XSDEntityResolver(String baseDir) { this.xsdBaseDir = baseDir; } @Override public InputSource resolveEntity(String publicId, String systemId) throws IOException { // 从systemId中提取文件名,比如处理类似"segment-defs.xsd"的引用 String fileName = new File(systemId).getName(); File targetFile = new File(xsdBaseDir + File.separator + fileName); if (targetFile.exists() && targetFile.isFile()) { return new InputSource(new FileInputStream(targetFile)); } // 如果找不到,返回null让SAX用默认逻辑处理 return null; } }
然后把这个解析器绑定到你的SAXParser上:
import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); // HL7 XSD依赖命名空间,必须开启 factory.setValidating(true); // 开启验证才会触发外部引用的解析 SAXParser parser = factory.newSAXParser(); parser.getXMLReader().setEntityResolver(new HL7XSDEntityResolver("/path/to/your/xsd/folder")); // 之后正常解析主消息XSD文件 parser.parse(new File("/path/to/message-defs.xsd"), yourCustomContentHandler);
2. 用SchemaFactory加载完整Schema(更省心)
如果你不需要手动逐节点解析,而是要处理完整的XSD结构,用SchemaFactory会更靠谱——它专门处理XSD的依赖关系,会自动解析所有<include>/<import>的外部文件:
import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.XMLConstants; import java.io.File; SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // 加载主消息XSD,SchemaFactory会自动跟进所有引用的段定义XSD Schema hl7Schema = schemaFactory.newSchema(new File("/path/to/message-defs.xsd")); // 之后你可以用这个schema创建验证器,或者获取SchemaModel来处理结构 // 比如获取所有的元素定义: // SchemaModel model = ((DOMSchemaModel) hl7Schema).getSchemaModel();
这种方式不需要手动处理引用路径,只要你的XSD里的schemaLocation路径正确(相对路径是相对于主XSD的位置,不是代码运行目录),就能自动加载外部文件。
3. 检查XSD里的引用配置
先确认你的XSD引用写法没问题:
- 如果是同命名空间的段定义,用
<xs:include schemaLocation="segment-defs.xsd"/>,确保schemaLocation的相对路径正确 - 如果是不同命名空间,用
<xs:import namespace="your-segment-namespace" schemaLocation="segment-defs.xsd"/>,要保证命名空间和schemaLocation对应
4. 调整原示例代码的解析逻辑
如果你坚持用原示例的SAX手动解析逻辑,需要在ContentHandler的startElement方法里,主动处理<xs:include>和<xs:import>元素:
@Override public void startElement(String uri, String localName, String qName, Attributes attributes) { if ("include".equals(localName) || "import".equals(localName)) { String schemaLoc = attributes.getValue("schemaLocation"); if (schemaLoc != null) { // 加载对应的段定义XSD文件,递归调用SAX解析 parseXsdFile(schemaLoc); } } // 其他节点的处理逻辑... }
这样当SAX解析到引用元素时,会手动加载并解析外部XSD文件,就能把段定义也纳入处理了。
内容的提问来源于stack exchange,提问作者svager
相关产品推荐
相关产品推荐

