如何忽略XML Schema导入并本地加载依赖文件?
解决W3C XSD远程导入限流导致的验证缓慢问题
我之前也碰到过一模一样的情况,W3C对这些官方XSD文件的限流确实会让验证过程慢得离谱。好在我们有两种靠谱的方法可以绕开远程请求,直接用你本地已经下载好的XSD文件:
方法一:自定义资源解析器(无需修改原XSD文件)
这个方法的核心是给SchemaFactory设置一个自定义的资源解析器,让它遇到指定命名空间的导入请求时,直接返回本地的文件流,而不是去远程拉取。
步骤1:实现LSResourceResolver类
import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import java.io.FileInputStream; import java.io.InputStream; import java.io.StringReader; public class LocalXsdResourceResolver implements LSResourceResolver { @Override public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { // 匹配XML命名空间,返回本地的xml.xsd if ("http://www.w3.org/XML/1998/namespace".equals(namespaceURI)) { try { return createLSInput(new FileInputStream("data/xml.xsd")); } catch (Exception e) { e.printStackTrace(); } } // 匹配XML-DSig命名空间,返回本地的xmldsig-core-schema.xsd if ("http://www.w3.org/2000/09/xmldsig#".equals(namespaceURI)) { try { return createLSInput(new FileInputStream("data/xmldsig-core-schema.xsd")); } catch (Exception e) { e.printStackTrace(); } } // 其他情况交给默认解析器处理 return null; } private LSInput createLSInput(InputStream inputStream) throws Exception { LSInput lsInput = new org.apache.xerces.dom.DOMInputImpl(); lsInput.setByteStream(inputStream); // 可选:设置字符流,确保编码正确 lsInput.setCharacterStream(new StringReader(new String(inputStream.readAllBytes()))); return lsInput; } }
步骤2:修改你的Schema加载代码
在创建SchemaFactory之后,添加自定义解析器的设置:
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newDefaultInstance(); dbFactory.setNamespaceAware(true); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); StreamSource[] resources = new StreamSource[3]; resources[0] = new StreamSource(new FileInputStream("data/TSL_schema.xsd")); resources[1] = new StreamSource(new FileInputStream("data/xml.xsd")); resources[2] = new StreamSource(new FileInputStream("data/xmldsig-core-schema.xsd")); SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // 关键:设置自定义资源解析器 schemaFactory.setResourceResolver(new LocalXsdResourceResolver()); Schema schema = schemaFactory.newSchema(resources); schema.newValidator().validate(new StreamSource(file)); dbFactory.setSchema(schema); this.document = dBuilder.parse(file);
方法二:直接修改TSL_schema.xsd的导入路径(简单粗暴)
如果你有权限修改原有的TSL_schema.xsd文件,可以直接把里面的远程schemaLocation改成本地文件的相对路径:
<!-- 原来的远程导入 --> <!-- <xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/> --> <!-- <xsd:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"/> --> <!-- 修改为本地路径 --> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/> <xsd:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsig-core-schema.xsd"/>
只要这两个本地XSD文件和TSL_schema.xsd在同一目录(或者你写对相对/绝对路径),SchemaFactory就会直接加载本地文件,完全不会触发远程请求。
两种方法各有优劣:方法一不用修改原文件,更适合不能改动XSD的场景;方法二更简单,适合有权限修改原文件的情况。
内容的提问来源于stack exchange,提问作者emilanov
相关产品推荐
相关产品推荐

