java - XSD 验证使用 XPath 向 XML 节点抛出异常
问题描述
我正在尝试针对 XSD 实施 XML 验证,该验证应该使用 XPath 捕获所有违反 XSD 的 XML 节点的违规行为。我的代码:
package com.xsdvalidator.poc;
import java.io.File;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.xml.XMLConstants;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
public class Xsd_Validator {
static int errorCount = 0;
static List<String> errors = new ArrayList<String>();
static Validator validator = null;
public static String Validate(String xmlString, String xsdPath, String delimeter) {
try {
if (validator == null) {
loadSchema(xsdPath);
}
SAXSource source = new SAXSource(new InputSource(new StringReader(xmlString)));
validator.validate(source);
if (errorCount > 0) {
return "Error occurred (" + errorCount/2 + ") while validating XML. " + String.join(delimeter, errors);
}
} catch (Exception e) {
return "Error occurred while validating XML. " + e.toString();
} finally {
errorCount = 0;
errors = new ArrayList<String>();
}
return "";
}
private static void loadSchema(String name) throws SAXException {
String language = XMLConstants.W3C_XML_SCHEMA_NS_URI;
SchemaFactory factory = SchemaFactory.newInstance(language);
Schema schema = factory.newSchema(new File(name));
validator = schema.newValidator();
validator.setErrorHandler(new ExceptionCatcher());
}
static class ExceptionCatcher implements ErrorHandler {
public void fatalError(SAXParseException e) throws SAXException {
errors.add(e.toString());
errorCount++;
}
public void error(SAXParseException e) throws SAXException {
errors.add(e.getMessage());
errorCount++;
}
public void warning(SAXParseException e) throws SAXException {
errors.add(e.getMessage());
errorCount++;
}
}
}
XSD:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
elementFormDefault="qualified"
vc:minVersion="1.1">
<xsd:element name="Employees">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="1" ref="Employee" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Employee">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" ref="Name" />
<xsd:element maxOccurs="1" minOccurs="1" ref="EmployeeID" />
<xsd:element maxOccurs="1" minOccurs="1" ref="EmailID" />
<xsd:element maxOccurs="1" minOccurs="1" ref="PhoneNumber" />
<xsd:element maxOccurs="1" minOccurs="1" ref="JoiningDate" />
<xsd:element maxOccurs="1" minOccurs="0" ref="Work" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Name">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" type="FirstNameType" name="First" />
<xsd:element maxOccurs="1" minOccurs="0" type="MiddleNameType" name="Middle" />
<xsd:element maxOccurs="1" minOccurs="1" type="LastNameType" name="Last" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="EmployeeID" type="EmployeeIDType" />
<xsd:element name="EmailID" type="EmailType" />
<xsd:element name="PhoneNumber" type="PhoneNumberType" />
<xsd:element name="JoiningDate" type="xsd:dateTime" />
<xsd:element name="Work" type="WorkType" />
<!-- Custom Data Types -->
<xsd:simpleType name="FirstNameType">
<xsd:restriction base="xsd:string">
<xsd:whiteSpace value="collapse" />
<xsd:maxLength value="20" />
<xsd:minLength value="2" />
<xsd:pattern value="[A-Za-z ]+" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="MiddleNameType">
<xsd:restriction base="xsd:string">
<xsd:whiteSpace value="collapse" />
<xsd:length value="1"/>
<xsd:pattern value="[A-Za-z ]+" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="LastNameType">
<xsd:restriction base="xsd:string">
<xsd:whiteSpace value="collapse" />
<xsd:maxLength value="12" />
<xsd:minLength value="2" />
<xsd:pattern value="[A-Za-z ]+" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="EmployeeIDType">
<xsd:restriction base="xsd:integer">
<xsd:whiteSpace value="collapse" />
<xsd:pattern value="\d{1,12}" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="EmailType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[^@]+@[^\.]+\..+|" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="PhoneNumberType">
<xsd:restriction base="xsd:integer">
<xsd:whiteSpace value="collapse" />
<xsd:pattern value="\d{1,10}" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="WorkType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="PERMANENT"/>
<xsd:enumeration value="TEMPORARY"/>
<xsd:enumeration value="CONTRACT"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
示例 XML:
<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Employee>
<Name>
<First>Dev1</First>
<Middle>K</Middle>
<Last>Das</Last>
</Name>
<EmployeeID>12345</EmployeeID>
<EmailID>dev.d@email.com</EmailID>
<PhoneNumber>8777000000</PhoneNumber>
<JoiningDate>2019-10-31T10:00:00</JoiningDate>
<Work>PERMANENT</Work>
</Employee>
<Employee>
<Name>
<First>James</First>
<Last>Bond2</Last>
</Name>
<EmployeeID>121212</EmployeeID>
<EmailID>james.bond@email.com</EmailID>
<PhoneNumber>8777111111</PhoneNumber>
<JoiningDate>2019-10-31T10:00:00</JoiningDate>
<Work>PERMANENT</Work>
</Employee>
</Employees>
这给了我一个例外,例如:
Error occurred (2) while validating XML. cvc-pattern-valid: Value 'Dev1' is not facet-valid with respect to pattern '[A-Za-z ]+' for type 'FirstNameType'.¡cvc-type.3.1.3: The value 'Dev1' of element 'First' is not valid.¡cvc-pattern-valid: Value 'Bond2' is not facet-valid with respect to pattern '[A-Za-z ]+' for type 'LastNameType'.¡cvc-type.3.1.3: The value 'Bond2' of element 'Last' is not valid.
错误是正确的,但我想要违反规则的元素的 XPath。例如:
Error occurred (2) while validating XML. cvc-pattern-valid: Value 'Dev1' is not facet-valid with respect to pattern '[A-Za-z ]+' for type 'FirstNameType'.¡cvc-type.3.1.3: The value 'Dev1' of element '/Employees[1]/Employee[1]/Name[1]/First[1]' is not valid.¡cvc-pattern-valid: Value 'Bond2' is not facet-valid with respect to pattern '[A-Za-z ]+' for type 'LastNameType'.¡cvc-type.3.1.3: The value 'Bond2' of element '/Employees[1]/Employee[2]/Name[1]/Last[1]' is not valid.
可能吗?任何建议/代码都会有所帮助。谢谢。
解决方案
您实际上并没有说明您正在使用哪个模式验证器,并且 JAXP 规范没有定义 SAXParseException 中可能可用的所有细节。如果您使用的是 Saxon 的模式验证器,则异常对象可能包含两个路径(尽管详细信息没有详细记录):无效元素的路径和导致其无效的元素的路径。例如,如果 FOO 元素包含 FOO 的内容模型不允许的 BAR 元素,那么您将获得指向无效元素 (FOO) 的路径和指向错误位置 (BAR) 的路径。
推荐阅读
- java - Hazelcast CP 子系统 FencedLock 内存使用情况
- signalr - 在 Azure Function 中使用 JWT 进行无服务器 SignalR 身份验证
- java - 在 JavaFX 上动态添加和填充选项卡
- google-sheets - 如何根据标准与给定的总数返回结果?
- c - 假设分母<>0,整数除法是否会溢出/下溢?
- string - Scala如何从CSV中的特定列中查找所有唯一值?
- java - Weka Experimenter mod:创建要运行的实验副本时出现问题
- javascript - 调用函数时如何循环此 if 语句
- python - 如何在具有分类变量和连续变量的数据集中查找和计算相关性?
- android - Flutter App 在 Android 上因使用 Firebase Firestore 匿名登录而崩溃