2010-03-25 59 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