Java XML:如何禁用相对systemId的user.dir解析并保留原路径?
问题背景
示例XML:
<book xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/book.xsd" />
使用标准JAXP API(Xerces实现)解析上述XML时,xsd/book.xsd会被默认相对于当前用户目录解析为file:///home/user/xsd/book.xsd。当前通过EntityResolver2从绝对URI反推原始相对路径的临时方案不够规范,希望找到更优方案,比如禁用基于user.dir的解析行为,直接保留原始相对systemId。
优化方案
1. 实现XMLResolver直接获取原始相对路径
JAXP 1.4及以上版本引入的XMLResolver接口,其resolveResource方法可以直接拿到未被解析的原始相对systemId,无需从绝对URI反推,是更规范的处理方式:
XMLResolver customResolver = (type, namespace, publicId, systemId, baseURI) -> { // 直接使用原始的systemId(即xsd/book.xsd)执行自定义逻辑 if ("http://www.w3.org/2001/XMLSchema".equals(type) && "xsd/book.xsd".equals(systemId)) { // 示例:按自定义路径加载资源 return new FileInputStream(new File("your/target/path/" + systemId)); } // 其他场景交给默认解析逻辑 return null; }; // 为解析器配置自定义Resolver SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); XMLReader reader = parser.getXMLReader(); reader.setXMLResolver(customResolver);
2. 禁用外部资源加载(无需验证场景)
如果业务不需要加载外部Schema或DTD,可以直接禁用解析器的外部资源加载特性,这样解析器不会自动解析相对路径:
SAXParserFactory factory = SAXParserFactory.newInstance(); // 禁用外部DTD加载 factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); // 若不需要Schema验证,也可关闭Schema校验 factory.setFeature("http://apache.org/xml/features/validation/schema", false);
注意:该方案仅适用于不需要实际加载外部Schema的场景。
3. 显式设置解析器的基础URI(baseURI)
如果希望相对路径基于XML文件自身的位置而非user.dir,可以显式设置解析器的基础URI,让相对路径基于XML文件所在目录解析:
SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); XMLReader reader = parser.getXMLReader(); // 假设XML文件位于/path/to/xml/book.xml,设置baseURI为该文件的目录 reader.setProperty("http://apache.org/xml/properties/dom/document-base-uri", "file:///path/to/xml/");
此时xsd/book.xsd会被解析为file:///path/to/xml/xsd/book.xsd,这是更符合常规预期的解析逻辑——相对XML文件所在位置而非用户工作目录。
内容的提问来源于stack exchange,提问作者MRalwasser
相关产品推荐
相关产品推荐

