Java XML:如何通过JAXP强制xs:any通配符执行strict严格匹配
结论
可以实现,不需要修改磁盘上的原始XSD文件,通过JAXP生态的两种常用方案即可强制xs:any按processContents="strict"规则验证:
方案1:使用XSOM精准修改内存Schema模型(推荐)
XSOM是官方维护的XML Schema对象模型库,可以将XSD解析为可修改的内存对象树,精准调整xs:any的属性,不会误改其他内容:
- 第一步:引入XSOM依赖(Maven坐标如下)
<dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>xsom</artifactId> <version>4.0.4</version> </dependency>
- 第二步:解析原XSD并修改属性,示例代码:
import com.sun.xml.xsom.*; import com.sun.xml.xsom.parser.XSOMParser; import javax.xml.XMLConstants; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; // 解析原始外部XSD XSOMParser xsomParser = new XSOMParser(); xsomParser.parse(new File("your_original.xsd")); XSSchemaSet schemaSet = xsomParser.getResult(); // 遍历所有xs:any通配符节点修改processContents属性 schemaSet.getSchemas().forEach(schema -> { schema.getElementDecls().values().forEach(elemDecl -> { if (elemDecl.getType().isComplexType()) { XSComplexType complexType = elemDecl.getType().asComplexType(); XSParticle contentTypeParticle = complexType.getContentType().asParticle(); if (contentTypeParticle != null && contentTypeParticle.getTerm().isWildcard()) { XSWildcard wildcard = contentTypeParticle.getTerm().asWildcard(); // 从skip改为strict wildcard.setProcessContents(XSWildcard.PC_STRICT); } } }); }); // 生成修改后的Schema实例用于后续验证 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema modifiedSchema = schemaFactory.newSchema(schemaSet.generateDocument());
方案2:内存流拦截替换(无额外依赖)
如果不想引入第三方依赖,可以通过自定义LSResourceResolver在XSD加载阶段拦截原始内容,内存替换属性值后返回给解析器:
import org.w3c.dom.ls.*; import javax.xml.XMLConstants; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.io.StringReader; SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); schemaFactory.setResourceResolver(new LSResourceResolver() { @Override public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { try { // 读取原XSD文件内容 String rawContent = Files.readString(Paths.get(systemId), StandardCharsets.UTF_8); // 内存替换属性值 String modifiedContent = rawContent.replace("processContents=\"skip\"", "processContents=\"strict\""); // 构造LSInput返回给解析器 DOMImplementationLS domImpl = (DOMImplementationLS) DOMImplementationRegistry.newInstance().getDOMImplementation("LS"); LSInput lsInput = domImpl.createLSInput(); lsInput.setCharacterStream(new StringReader(modifiedContent)); lsInput.setSystemId(systemId); return lsInput; } catch (Exception e) { throw new RuntimeException("XSD内容替换失败", e); } } }); // 加载原XSD,解析器拿到的已经是替换后的内容 Schema modifiedSchema = schemaFactory.newSchema(new File("your_original.xsd"));
注意:该方案是全局字符串替换,若XSD注释或其他非属性位置出现
processContents="skip"字符串会被误替换,仅适合简单场景使用。
内容的提问来源于stack exchange,提问作者MRalwasser
相关产品推荐
相关产品推荐

