XML ファイルを XSD ファイルと比較して検証する最良の方法は何ですか?
-
08-06-2019 - |
質問
与えられた xsd ファイルに準拠する必要がある XML ファイルをいくつか生成しています。適合していることを確認する最良の方法は何ですか?
解決
Java ランタイム ライブラリは検証をサポートしています。私が最後にチェックしたとき、これは内部にある Apache Xerces パーサーでした。おそらく使用する必要があります javax.xml.validation.Validator.
import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import java.net.URL;
import org.xml.sax.SAXException;
//import java.io.File; // if you use File
import java.io.IOException;
...
URL schemaFile = new URL("http://host:port/filename.xsd");
// webapp example xsd:
// URL schemaFile = new URL("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd");
// local file example:
// File schemaFile = new File("/location/to/localfile.xsd"); // etc.
Source xmlFile = new StreamSource(new File("web.xml"));
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
validator.validate(xmlFile);
System.out.println(xmlFile.getSystemId() + " is valid");
} catch (SAXException e) {
System.out.println(xmlFile.getSystemId() + " is NOT valid reason:" + e);
} catch (IOException e) {}
スキーマ ファクトリ定数は文字列です http://www.w3.org/2001/XMLSchema
XSD を定義します。上記のコードは、URL に対して WAR デプロイメント記述子を検証します。 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
ただし、ローカル ファイルに対して簡単に検証することもできます。
ドキュメントの検証に DOMParser を使用しないでください (ドキュメント オブジェクト モデルを作成することが目的でない限り)。これにより、ドキュメントの解析時に DOM オブジェクトの作成が開始されますが、使用しない場合は無駄です。
他のヒント
これを使用してそれを行う方法は次のとおりです ゼルセス2. 。このためのチュートリアル、 ここ (必須サインアップ)。
元の帰属:~から露骨にコピーされた ここ:
import org.apache.xerces.parsers.DOMParser;
import java.io.File;
import org.w3c.dom.Document;
public class SchemaTest {
public static void main (String args[]) {
File docFile = new File("memory.xml");
try {
DOMParser parser = new DOMParser();
parser.setFeature("http://xml.org/sax/features/validation", true);
parser.setProperty(
"http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation",
"memory.xsd");
ErrorChecker errors = new ErrorChecker();
parser.setErrorHandler(errors);
parser.parse("memory.xml");
} catch (Exception e) {
System.out.print("Problem parsing the file.");
}
}
}
ant を使用してプロジェクトをビルドするので、schemavalidate タスクを使用して構成ファイルを確認できます。
<schemavalidate>
<fileset dir="${configdir}" includes="**/*.xml" />
</schemavalidate>
これで、不正な構成ファイルはビルドに失敗します。
これはよくある質問なので、Java は「参照された」xsd に対しても検証できることを指摘します。たとえば、.xml ファイル自体がヘッダーで XSD を指定している場合、次のようにします。 xsi:SchemaLocation
または xsi:noNamespaceSchemaLocation
(または特定の名前空間の場合は xsi) 元:
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.example.com/document.xsd">
...
または SchemaLocation (常に名前空間から xsd へのマッピングのリスト)
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:SchemaLocation="http://www.example.com/my_namespace http://www.example.com/document.xsd">
...
他の答えもここで同様に機能します。.xsd ファイルは、.xml ファイルで宣言された名前空間に「マップ」され、名前空間を宣言するため、.xml ファイル内の名前空間と一致する場合は問題ありません。しかし、カスタムできると便利な場合もあります。 リゾルバ...
Javadoc から:「URL、ファイル、またはソースを指定せずにスキーマを作成すると、Java 言語は検証中のドキュメント内を調べて使用するスキーマを見つけるスキーマを作成します。例えば:"
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Schema schema = factory.newSchema();
これは複数の名前空間などでも機能します。このアプローチの問題点は、 xmlsns:xsi
はおそらくネットワークの場所であるため、デフォルトですべての検証でネットワークにアクセスしますが、常に最適であるとは限りません。
以下は、XML ファイルが参照する XSD に対して XML ファイルを検証する例です (ネットワークから取得する必要がある場合でも)。
public static void verifyValidatesInternalXsd(String filename) throws Exception {
InputStream xmlStream = new new FileInputStream(filename);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(true);
factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new RaiseOnErrorHandler());
builder.parse(new InputSource(xmlStream));
xmlStream.close();
}
public static class RaiseOnErrorHandler implements ErrorHandler {
public void warning(SAXParseException e) throws SAXException {
throw new RuntimeException(e);
}
public void error(SAXParseException e) throws SAXException {
throw new RuntimeException(e);
}
public void fatalError(SAXParseException e) throws SAXException {
throw new RuntimeException(e);
}
}
xml ファイルが URL を参照している場合でも、xsd を手動で指定する (ここで他の回答を参照してください) か、「XML カタログ」を使用することで、参照された XSD をネットワークから取得することを回避できます。 スタイルリゾルバ. 。どうやら春も 傍受できる URL は、検証のためにローカル ファイルを提供することを要求します。または、独自に設定することもできます setResourceResolver, 、 元:
Source xmlFile = new StreamSource(xmlFileLocation);
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema();
Validator validator = schema.newValidator();
validator.setResourceResolver(new LSResourceResolver() {
@Override
public LSInput resolveResource(String type, String namespaceURI,
String publicId, String systemId, String baseURI) {
InputSource is = new InputSource(
getClass().getResourceAsStream(
"some_local_file_in_the_jar.xsd"));
// or lookup by URI, etc...
return new Input(is); // for class Input see
// https://stackoverflow.com/a/2342859/32453
}
});
validator.validate(xmlFile);
こちらも参照 ここ 別のチュートリアルのために。
デフォルトでは DOM 解析を使用することだと思いますが、検証する SAX パーサーを使用して同様のことを行うことができます。 同じように saxReader.setEntityResolver(your_resolver_here);
Java 7 を使用すると、次のドキュメントに従うことができます。 パッケージの説明.
// parse an XML document into a DOM tree DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = parser.parse(new File("instance.xml")); // create a SchemaFactory capable of understanding WXS schemas SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // load a WXS schema, represented by a Schema instance Source schemaFile = new StreamSource(new File("mySchema.xsd")); Schema schema = factory.newSchema(schemaFile); // create a Validator instance, which can be used to validate an instance document Validator validator = schema.newValidator(); // validate the DOM tree try { validator.validate(new DOMSource(document)); } catch (SAXException e) { // instance document is invalid! }
Linux マシンをお持ちの場合は、無料のコマンドライン ツール SAXCount を使用できます。これはとても便利だと思いました。
SAXCount -f -s -n my.xml
dtd および xsd に対して検証されます。50MBのファイルの場合は5秒。
Debian Squeeze では、「libxerces-c-samples」パッケージにあります。
dtd と xsd の定義は XML 内に存在する必要があります。それらを個別に構成することはできません。
もう一つの答え:ファイルを検証する必要があると言ったので、 生成する (書き込み) 場合は、最初に書いてから検証のために読み戻すのではなく、書き込み中にコンテンツを検証したい場合があります。SAX ベースのライターを使用している場合は、Xml 検証用の JDK API を使用してこれを実行できる可能性があります。その場合は、「Validator.validate(source, result)」を呼び出してバリデーターにリンクするだけです。ソースはライターから取得され、result は出力が必要な場所になります。
あるいは、コンテンツの作成に Stax を使用する場合 (または、Stax を使用する、または使用できるライブラリ)、 ウッドストックス XMLStreamWriter を使用する場合、検証を直接サポートすることもできます。ここにあります ブログの記事 それがどのように行われるかを示します:
JAXB では、次のコードを使用できます。
@Test
public void testCheckXmlIsValidAgainstSchema() {
logger.info("Validating an XML file against the latest schema...");
MyValidationEventCollector vec = new MyValidationEventCollector();
validateXmlAgainstSchema(vec, inputXmlFileName, inputXmlSchemaName, inputXmlRootClass);
assertThat(vec.getValidationErrors().isEmpty(), is(expectedValidationResult));
}
private void validateXmlAgainstSchema(final MyValidationEventCollector vec, final String xmlFileName, final String xsdSchemaName, final Class<?> rootClass) {
try (InputStream xmlFileIs = Thread.currentThread().getContextClassLoader().getResourceAsStream(xmlFileName);) {
final JAXBContext jContext = JAXBContext.newInstance(rootClass);
// Unmarshal the data from InputStream
final Unmarshaller unmarshaller = jContext.createUnmarshaller();
final SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
final InputStream schemaAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(xsdSchemaName);
unmarshaller.setSchema(sf.newSchema(new StreamSource(schemaAsStream)));
unmarshaller.setEventHandler(vec);
unmarshaller.unmarshal(new StreamSource(xmlFileIs), rootClass).getValue(); // The Document class is the root object in the XML file you want to validate
for (String validationError : vec.getValidationErrors()) {
logger.trace(validationError);
}
} catch (final Exception e) {
logger.error("The validation of the XML file " + xmlFileName + " failed: ", e);
}
}
class MyValidationEventCollector implements ValidationEventHandler {
private final List<String> validationErrors;
public MyValidationEventCollector() {
validationErrors = new ArrayList<>();
}
public List<String> getValidationErrors() {
return Collections.unmodifiableList(validationErrors);
}
@Override
public boolean handleEvent(final ValidationEvent event) {
String pattern = "line {0}, column {1}, error message {2}";
String errorMessage = MessageFormat.format(pattern, event.getLocator().getLineNumber(), event.getLocator().getColumnNumber(),
event.getMessage());
if (event.getSeverity() == ValidationEvent.FATAL_ERROR) {
validationErrors.add(errorMessage);
}
return true; // you collect the validation errors in a List and handle them later
}
}
オンライン スキーマに対して検証する
Source xmlFile = new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream("your.xml"));
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(Thread.currentThread().getContextClassLoader().getResource("your.xsd"));
Validator validator = schema.newValidator();
validator.validate(xmlFile);
ローカルスキーマに対して検証する
XML を XSD に対して 1 回だけ検証する必要があったので、XMLFox を試してみました。とても混乱していて奇妙だと思いました。ヘルプの説明がインターフェイスと一致していないようでした。
私は最終的に LiquidXML Studio 2008 (v6) を使用しました。これははるかに使いやすく、すぐに馴染みました (UI は私が頻繁に使用する Visual Basic 2008 Express に非常に似ています)。欠点:無料版には検証機能がないため、30 日間の試用版を使用する必要がありました。