[英]Validation in Java of an XML file using more schemas, but against only one of those schemas
[英]XML Validation with non local schemas
目前我參與了一個項目,其中我必須驗證 XML 文件。 文件將由用戶通過 REST API 上傳,該文件用 Java 與 Z38008FECDD81C2F4D1D79Z 編寫。 架構文件位於 XML 文件 [2] 中的 URL[1] 作為屬性“schemaLocation”。 XSD 文件也可能包含多個其他模式文件。 用戶上傳的文件是 IO-Link 設備描述 (IODD) 文件。
所以,我目前的問題是在主模式中加載包含的驗證方案。 下載模式並使用它們進行驗證不是我的目標。 整個過程必須是動態的。 我也不想使用 IO-Link 本身提供的 IODDChecker。
我讀到這可以通過 ResourceResolver 接口完成,但我找不到任何實現來通過 URL 或類似的東西從主模式加載包含的模式。
那么,您能幫我找到解決該問題的方法嗎?
先感謝您!
這是驗證文件的方法:
public boolean isValid(String file) {
if (file == null || file.isEmpty() || !Files.exists(Path.of(file)) || !Files.isReadable(Path.of(file)))
return false;
else if (this.getStamp() == null || this.getStamp().getChecker() == null)
return false;
else if (this.getStamp().getCrc().isEmpty())
return false;
try {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
factory.setErrorHandler(new LineNumberErrorHandler());
Schema schema = factory.newSchema(XsdReceiver.receive(this.schemaLocation));
Validator validator = schema.newValidator();
//validator.validate(new StreamSource(new ByteArrayInputStream(data)));
validator.setResourceResolver(factory.getResourceResolver());
validator.validate(new StreamSource(new File(file)));
} catch (Exception e) {
return false;
}
return true;
}
這是模式接收器方法。 它可以工作,但是當架構包含時,驗證過程就會失敗。 (此代碼下方的錯誤消息。
public static Source receive(String url) {
url = url.contains(" ") ? url.replace(" ", "/") : url;
try {
URL u = new URL(url);
HttpURLConnection c = (HttpURLConnection)u.openConnection();
int status = c.getResponseCode();
if (status == HttpURLConnection.HTTP_MOVED_TEMP
|| status == HttpURLConnection.HTTP_MOVED_PERM
|| status == HttpURLConnection.HTTP_SEE_OTHER
)
c = (HttpURLConnection) new URL(c.getHeaderField("Location")).openConnection();
return new StreamSource(c.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
我從驗證器收到的錯誤消息。
Line: 3) schema_reference.4: Failed to read schema document 'IODD-Primitives1.1.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
Line: 4) schema_reference.4: Failed to read schema document 'IODD-Datatypes1.1.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
Line: 5) schema_reference.4: Failed to read schema document 'IODD-Variables1.1.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
Line: 6) schema_reference.4: Failed to read schema document 'IODD-Events1.1.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
Line: 7) schema_reference.4: Failed to read schema document 'IODD-UserInterface1.1.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
Line: 8) schema_reference.4: Failed to read schema document 'IODD-Communication1.1.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
Line: 180) src-resolve: Cannot resolve the name 'DeviceIdT' to a(n) 'type definition' component.
Line: 180) src-resolve: Cannot resolve the name 'DeviceIdT' to a(n) 'simpleType definition' component.
Line: 191) src-resolve: Cannot resolve the name 'DeviceIdT' to a(n) 'type definition' component.
Line: 228) src-resolve: Cannot resolve the name 'CollectionT' to a(n) 'type definition' component.
Line: 292) src-resolve: Cannot resolve the name 'ObjectT' to a(n) 'type definition' component.
Line: 303) src-resolve: Cannot resolve the name 'CollectionT' to a(n) 'type definition' component.
Line: 312) src-resolve: Cannot resolve the name 'DataItemT' to a(n) 'type definition' component.
Line: 12) src-resolve: Cannot resolve the name 'DocumentInfoT' to a(n) 'type definition' component.
Line: 15) src-resolve: Cannot resolve the name 'CommNetworkProfileT' to a(n) 'type definition' component.
Line: 16) src-resolve: Cannot resolve the name 'ExternalTextCollectionT' to a(n) 'type definition' component.
Line: 22) src-resolve: Cannot resolve the name 'StampT' to a(n) 'type definition' component.
Line: 152) src-resolve: Cannot resolve the name 'TextRefT' to a(n) 'type definition' component.
Line: 153) src-resolve: Cannot resolve the name 'TextRefT' to a(n) 'type definition' component.
Line: 168) src-resolve: Cannot resolve the name 'TextRefT' to a(n) 'type definition' component.
Line: 169) src-resolve: Cannot resolve the name 'TextRefT' to a(n) 'type definition' component.
Line: 195) src-resolve: Cannot resolve the name 'TextRefT' to a(n) 'type definition' component.
Line: 196) src-resolve: Cannot resolve the name 'TextRefT' to a(n) 'type definition' component.
Line: 238) src-resolve: Cannot resolve the name 'DatatypeCollectionT' to a(n) 'type definition' component.
Line: 239) src-resolve: Cannot resolve the name 'VariableCollectionT' to a(n) 'type definition' component.
Line: 250) src-resolve: Cannot resolve the name 'ErrorTypeCollectionT' to a(n) 'type definition' component.
Line: 257) src-resolve: Cannot resolve the name 'EventCollectionT' to a(n) 'type definition' component.
Line: 263) src-resolve: Cannot resolve the name 'UserInterfaceT' to a(n) 'type definition' component.
[1] https://www.io-link.com/IODD/2010/10/IODD1.1.xsd
[2] https://ioddfinder.io-link.com/productvariants/search/11765 (以IO-Link產品TV7105為例)
好的,我自己解決了這個問題。 簡而言之,我必須創建一個 class 實現接口LSResourceResolver
並覆蓋方法resolveResource
。
長答案是:
首先,我創建了 class XsdReceiver
並讓它實現接口LSResourceResolver
。 現在還必須覆蓋方法resolveResource
。 該方法最終負責查詢丟失的 XSD 文件並將它們作為資源LSInput
返回。 (與LSResourceResolver
一樣, LSInput
是一個接口,因此必須作為單獨的 class 實現。我簡單地稱它為Input
)。 最后,我使用了setResourceResolver
方法並將創建的 class XsdReceiver
作為參數實例化。
功能:
方法isValid
應該檢查 XML 模式的有效性等。 必要的模式文件可以在根標簽中找到。 它還必須手動傳遞給SchemaFactory
class。 在調用該方法並讀取主模式文件后,每個引用的 XML 或 XSD 文件都會自動傳遞給方法resolveResource
。 SchemaFactory
class 為我們完成了這項工作。
玩得開心:D
public boolean isValid(byte[] data) {
if (this.getStamp() == null || this.getStamp().getChecker() == null)
return false;
else if (this.getStamp().getCrc().isEmpty())
return false;
try {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
factory.setErrorHandler(new LineNumberErrorHandler());
factory.setResourceResolver(new XsdReceiver());
Schema schema = factory.newSchema(XsdReceiver.receive(this.schemaLocation));
Validator validator = schema.newValidator();
validator.setResourceResolver(factory.getResourceResolver());
validator.validate(new StreamSource(new ByteArrayInputStream(data)));
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public class XsdReceiver implements LSResourceResolver {
public static Source receive(String url) {
url = url.contains(" ") ? url.replace(" ", "/") : url;
HttpURLConnection c = XsdReceiver.followRedirection(url);
if (c == null)
return null;
try {
return new StreamSource(c.getInputStream());
} catch (IOException e) {
return null;
}
}
private static HttpURLConnection followRedirection(String url) {
HttpURLConnection c = null;
try {
URL u = new URL(url);
c = (HttpURLConnection)u.openConnection();
int status = c.getResponseCode();
if (status == HttpURLConnection.HTTP_MOVED_TEMP
|| status == HttpURLConnection.HTTP_MOVED_PERM
|| status == HttpURLConnection.HTTP_SEE_OTHER
)
c = (HttpURLConnection) new URL(c.getHeaderField("Location")).openConnection();
} catch (IOException e) {
return null;
}
return c;
}
@Override
public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
if (namespaceURI == null || type.equals("http://www.w3.org/TR/REC-xml"))
return null;
if (systemId.equals("xml.xsd")) {
try {
File f = ResourceUtils.getFile("classpath:data/xml.xsd");
return new Input(StandardCharsets.UTF_8.name(), new FileInputStream(f), null, systemId, publicId, namespaceURI, true, null);
} catch (IOException e) {
return null;
}
}
String file = String.join("/", namespaceURI, systemId);
HttpURLConnection connection;
Input i = null;
connection = XsdReceiver.followRedirection(file);
if (connection == null)
return null;
try {
i = new Input(StandardCharsets.UTF_8.name(), connection.getInputStream(), null, systemId, publicId, namespaceURI, true, null);
} catch (IOException e) {
return null;
}
return i;
}
}
public class Input implements LSInput {
private String encoding;
private InputStream byteStream;
private String stringData;
private String systemId;
private String publicId;
private String baseUri;
boolean certifiedText;
private Reader characterStream;
public Input(String encoding, InputStream byteStream, String stringData, String systemId, String publicId, String baseUri, boolean certifiedText, Reader characterStream) {
this.encoding = encoding;
this.byteStream = byteStream;
this.stringData = stringData;
this.systemId = systemId;
this.publicId = publicId;
this.baseUri = baseUri;
this.certifiedText = certifiedText;
this.characterStream = characterStream;
}
@Override
public Reader getCharacterStream() {
return this.characterStream;
}
@Override
public void setCharacterStream(Reader characterStream) {
this.characterStream = characterStream;
}
@Override
public InputStream getByteStream() {
return this.byteStream;
}
@Override
public void setByteStream(InputStream byteStream) {
this.byteStream = byteStream;
}
@Override
public String getStringData() {
return this.stringData;
}
@Override
public void setStringData(String stringData) {
this.stringData = stringData;
}
@Override
public String getSystemId() {
return this.systemId;
}
@Override
public void setSystemId(String systemId) {
this.systemId = systemId;
}
@Override
public String getPublicId() {
return this.publicId;
}
@Override
public void setPublicId(String publicId) {
this.publicId = publicId;
}
@Override
public String getBaseURI() {
return this.baseUri;
}
@Override
public void setBaseURI(String baseURI) {
this.baseUri = baseURI;
}
@Override
public String getEncoding() {
return this.encoding;
}
@Override
public void setEncoding(String encoding) {
this.encoding = encoding;
}
@Override
public boolean getCertifiedText() {
return this.certifiedText;
}
@Override
public void setCertifiedText(boolean certifiedText) {
this.certifiedText = certifiedText;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.