2010-03-25 92 views
17

这是我第一次尝试使用XSD验证XML。使用.NET进行XSD验证

的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文件中的 “架构/ 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. 

任何照明,将不胜感激。

回答

26

而不是使用XDocument.Validate扩展方法,我会使用XmlReader,它可以配置为通过XmlReaderSettings处理内联模式。你可以做下面的代码。

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 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"> 
+0

第一个答案适用于我,除了它在这里缺少错误处理://解析文件将导致验证发生。而(读者。Read());没有捕获到一些错误(如拥有XML元素的开始,但没有其他错误)。更糟糕的是,它们甚至不会在调用代码中引发异常。 – 2012-03-12 18:12:56

2

您提取模式位置的代码看起来很奇怪。为什么获得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); 
         }); 
+0

我不知道的xmlns是什么。我甚至需要它吗?我只是想正确指向要验证文档的模式位置。 – 2010-03-28 20:18:26

+0

我认为你不应该需要xmlns属性的值。如上所示使用'xsi +“noNamespaceSchemaLocation”'。 – dtb 2010-03-28 20:20:27

+0

为了记录,* xml解析器*使用xmlns来知道'xsi:noNamespaceSchemaLocation'中的'xsi'指向模式'http:// www.w3.org/2001/XMLSchema-instance'。文档解析后,使用'XNamespace'来引用命名空间,'xmlns'属性不再相关。 – Zarat 2016-01-14 14:16:09

14

以下是出来工作的样品:

用法:

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元素):

Errors http://www.freeimagehosting.net/uploads/01a570ce8b.jpg

你也可以尝试的逆过程;尝试从你的xml生成模式,并与你的实际xsd进行比较 - 看看差异;最简单的方法是使用VS IDE生成模式。以下是你如何做到这一点:

Create XSD from XML http://i44.tinypic.com/15yhto3.jpg

希望这有助于。

- 编辑 -

这是在约翰的要求,请使用非不赞成的方法看更新的代码:

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"); 

的Test2 .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> 

这是保证工作!

+5

-10!没有使用块,“新的XmlTextReader()”被弃用,“新的XmlValidatingReader()”被弃用,XmlSchemaCollection实际上已经过时!你使用.NET 1.1吗? – 2010-03-31 14:04:25

+0

@John:这是解决问题的方法;该操作没有为该代码指定任何特定的版本。尽管如此,我已经照顾你的顾虑并添加了更新的代码。请参阅编辑。 – 2010-04-01 05:41:08

+1

如果有人没有指定一个版本,那么说它们并不意味着.NET 1.1是很安全的!你应该假设他们至少使用.NET 2.0。我正在删除downvote。 – 2010-04-01 08:29:47