.NET を使用した XSD 検証の開始
-
22-09-2019 - |
質問
これは、XSD を使用して XML を検証する最初の試みです。
検証する XML ファイル:
<?xml version="1.0" encoding="utf-8" ?>
<config xmlns="Schemas" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="config.xsd">
<levelVariant>
<filePath>SampleVariant</filePath>
</levelVariant>
<levelVariant>
<filePath>LegendaryMode</filePath>
</levelVariant>
<levelVariant>
<filePath>AmazingMode</filePath>
</levelVariant>
</config>
XSD は、検証対象の XML ファイルに関連する「Schemas/config.xsd」にあります。
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="config">
<xs:complexType>
<xs:sequence>
<xs:element name="levelVariant">
<xs:complexType>
<xs:sequence>
<xs:element name="filePath" type="xs:anyURI">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
現時点では、XML ファイルを現在の表示どおりに正確に検証したいだけです。これをもっと理解できたら、さらに拡張していきます。現在存在する XML ファイルのような単純なものに、本当に多くの行が必要なのでしょうか?
C# の検証コード:
public void SetURI(string uri)
{
XElement toValidate = XElement.Load(Path.Combine(PATH_TO_DATA_DIR, uri) + ".xml");
// begin confusion
// exception here
string schemaURI = toValidate.Attributes("xmlns").First().ToString()
+ toValidate.Attributes("xsi:noNamespaceSchemaLocation").First().ToString();
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(null, schemaURI);
XDocument toValidateDoc = new XDocument(toValidate);
toValidateDoc.Validate(schemas, null);
// end confusion
root = toValidate;
}
上記のコードを実行すると、次の例外が発生します。
The ':' character, hexadecimal value 0x3A, cannot be included in a name.
どのような照明でも歓迎いたします。
解決
を使用するのではなく、 XDocument.Validate 拡張メソッドの場合、私は Xmlリーダー これは、インライン スキーマを処理するように構成できます。 XmlReader設定. 。次のコードのようなことを行うことができます。
public void VerifyXmlFile(string path)
{
// configure the xmlreader validation to use inline schema.
XmlReaderSettings config = new XmlReaderSettings();
config.ValidationType = ValidationType.Schema;
config.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
config.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
config.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
config.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
// Get the XmlReader object with the configured settings.
XmlReader reader = XmlReader.Create(path, config);
// Parsing the file will cause the validation to occur.
while (reader.Read()) ;
}
private void ValidationCallBack(object sender, ValidationEventArgs vea)
{
if (vea.Severity == XmlSeverityType.Warning)
Console.WriteLine(
"\tWarning: Matching schema not found. No validation occurred. {0}",
vea.Message);
else
Console.WriteLine("\tValidation error: {0}", vea.Message);
}
上記のコードは、次の using ステートメントを前提としています。
using System.Xml;
using System.Xml.Schema;
これを簡単にするために、私は何も返しませんでした boolean
または検証エラーのコレクションの場合は、これを簡単に変更してそうすることができます。
注記:config.xml と config.xsd を変更して検証できるようにしました。これらは私が行った変更です。
config.xsd:
<xs:element maxOccurs="unbounded" name="levelVariant">
config.xml:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="config.xsd">
他のヒント
以下は動作サンプルの一部です。
使用法:
XMLValidator val = new XMLValidator();
if (!val.IsValidXml(File.ReadAllText(@"d:\Test2.xml"), @"D:\Test2.xsd"))
MessageBox.Show(val.Errors);
クラス:
public class CXmlValidator
{
private int nErrors = 0;
private string strErrorMsg = string.Empty;
public string Errors { get { return strErrorMsg; } }
public void ValidationHandler(object sender, ValidationEventArgs args)
{
nErrors++;
strErrorMsg = strErrorMsg + args.Message + "\r\n";
}
public bool IsValidXml(string strXml/*xml in text*/, string strXsdLocation /*Xsd location*/)
{
bool bStatus = false;
try
{
// Declare local objects
XmlTextReader xtrReader = new XmlTextReader(strXsdLocation);
XmlSchemaCollection xcSchemaCollection = new XmlSchemaCollection();
xcSchemaCollection.Add(null/*add your namespace string*/, xtrReader);//Add multiple schemas if you want.
XmlValidatingReader vrValidator = new XmlValidatingReader(strXml, XmlNodeType.Document, null);
vrValidator.Schemas.Add(xcSchemaCollection);
// Add validation event handler
vrValidator.ValidationType = ValidationType.Schema;
vrValidator.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);
//Actual validation, read conforming the schema.
while (vrValidator.Read()) ;
vrValidator.Close();//Cleanup
//Exception if error.
if (nErrors > 0) { throw new Exception(strErrorMsg); }
else { bStatus = true; }//Success
}
catch (Exception error) { bStatus = false; }
return bStatus;
}
}
上記のコードは、次の xml(code3) を xsd(code4) に対して検証します。
<!--CODE 3 - TEST1.XML-->
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test1.xsd">
<name>My Name</name>
<street>1, My Street Address</street>
<city>Far</city>
<country>Mali</country>
</address>
<!--CODE 4 - TEST1.XSD-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
xml/xsd に対して検証すると、あなたとは異なるエラーが発生します。これは、ここから続行(xml 要素の追加/削除)するのに役立つと思います。
逆のプロセスを試すこともできます。XML からスキーマを生成して実際の xsd と比較してみて、違いを確認してください。これを行う最も簡単な方法は、VS IDE を使用してスキーマを生成することです。その方法は次のとおりです。
お役に立てれば。
- 編集 -
これは John のリクエストによるものです。非推奨でないメソッドを使用した更新されたコードを参照してください。
public bool IsValidXmlEx(string strXmlLocation, string strXsdLocation)
{
bool bStatus = false;
try
{
// Declare local objects
XmlReaderSettings rs = new XmlReaderSettings();
rs.ValidationType = ValidationType.Schema;
rs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation | XmlSchemaValidationFlags.ReportValidationWarnings;
rs.ValidationEventHandler += new ValidationEventHandler(rs_ValidationEventHandler);
rs.Schemas.Add(null, XmlReader.Create(strXsdLocation));
using (XmlReader xmlValidatingReader = XmlReader.Create(strXmlLocation, rs))
{ while (xmlValidatingReader.Read()) { } }
////Exception if error.
if (nErrors > 0) { throw new Exception(strErrorMsg); }
else { bStatus = true; }//Success
}
catch (Exception error) { bStatus = false; }
return bStatus;
}
void rs_ValidationEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Warning) strErrorMsg += "WARNING: " + Environment.NewLine;
else strErrorMsg += "ERROR: " + Environment.NewLine;
nErrors++;
strErrorMsg = strErrorMsg + e.Exception.Message + "\r\n";
}
使用法:
if (!val.IsValidXmlEx(@"d:\Test2.xml", @"D:\Test2.xsd"))
MessageBox.Show(val.Errors);
else
MessageBox.Show("Success");
テスト2.XML
<?xml version="1.0" encoding="utf-8" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test2.xsd">
<levelVariant>
<filePath>SampleVariant</filePath>
</levelVariant>
<levelVariant>
<filePath>LegendaryMode</filePath>
</levelVariant>
<levelVariant>
<filePath>AmazingMode</filePath>
</levelVariant>
</config>
Test2.XSD (VS IDE から生成)
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="config">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="levelVariant">
<xs:complexType>
<xs:sequence>
<xs:element name="filePath" type="xs:anyURI">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
これは確実に動作します。
は、スキーマの場所を抽出するあなたのコードは奇妙に見えます。なぜあなたはのxmlns属性の値を取得し、XSIの値とを連結します:noNamespaceSchemaLocation属性?例外は、あなたが属性への呼び出しで接頭辞を指定できないことに起因します。あなたが希望XNamespaceを指定する必要があります。
この(未テスト)を試してみてください
// Load document
XDocument doc = XDocument.Load("file.xml");
// Extract value of xsi:noNamespaceSchemaLocation
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
string schemaURI = (string)doc.Root.Attribute(xsi + "noNamespaceSchemaLocation");
// Create schema set
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("Schemas", schemaURI);
// Validate
doc.Validate(schemas, (o, e) =>
{
Console.WriteLine("{0}", e.Message);
});