2014-01-22 110 views
2

我正在爲我的類的自定義(de)序列化邏輯實現IXmlSerializable,但希望根據XSD模式檢查XML的讀寫情況。我已經加入了XmlSchemaProviderAttributeIXmlSerializable針對Schema進行驗證

[XmlSchemaProvider("ConfigSchema")] 
[XmlRoot("Config")] 
public class Config 
{ 
    // properties, fields and methods incl. interface methods 

    public static XmlQualifiedName ConfigSchema(XmlSchemaSet xs) 
    { 
     const string xsdPath = "./Config.xsd"; 

     var serializer = new XmlSerializer(typeof(XmlSchema)); 
     var schema = (XmlSchema)serializer.Deserialize(new XmlTextReader(xsdPath), null); 

     xs.XmlResolver = new XmlUrlResolver(); 
     xs.Add(schema); 

     return new XmlQualifiedName("Config", "namespace"); 
    } 
} 

架構加載罰款和(反)序列化工作正常,但沒有驗證。

<?xml version="1.0" encoding="utf-8"?> 
<xs:schema id="ConfigSchema" 
    targetNamespace="namespace" 
    elementFormDefault="qualified" 
    xmlns="namespace" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:complexType name="Config"> 
     <xs:all> 
      <xs:element name="Config"> 
       <xs:complexType> 
        <xs:all> 
         <xs:element name="name" type="xs:string" /> 
         <xs:element name="timeout" type="xs:time" /> 
         <xs:element name="points" minOccurs="1"> 
          <xs:complexType> 
           <xs:sequence> 
            <xs:element name="point" minOccurs="1" maxOccurs="unbounded"> 
             <xs:complexType> 
              <xs:all> 
               <xs:element name="a" type="xs:int" /> 
               <xs:element name="b" type="xs:int" /> 
               <xs:element name="c" type="xs:int" /> 
              </xs:all> 
             </xs:complexType> 
            </xs:element> 
           </xs:sequence> 
          </xs:complexType> 
         </xs:element> 
        </xs:all> 
       </xs:complexType> 
      </xs:element> 
     </xs:all> 
    </xs:complexType> 
</xs:schema> 

如果我反序列化對上面的架構沒有異常被拋出以下(<timeout>在架構中失蹤,但指定<xs:all>下):

<?xml version="1.0" encoding="utf-8" ?> 
    <Config 
     xmlns:xsi="http://w3.org/2001/XMLScehma-instance" 
     xsi:schemaLocation="namespace Config.xsd"> 
     <name>some name</name> 
     ... 

編輯:下面是我運行它

string path = "./serviceconfig.xml"; 
var serializer = new XmlSerializer(typeof(Config)); 
var cfg = (Config)serializer.Deserialize(new XmlTextReader(path), null); 

什麼是「正確」/「最好」的方式來驗證輸入/輸出XML反對e模式?

編輯#2:更多信息

下面是完整的XML

<?xml version="1.0" encoding="utf-8" ?> 
    <Config 
     xmlns:xsi="http://w3.org/2001/XMLScehma-instance" 
     xsi:schemaLocation="namespace Config.xsd"> 
     <name>some name</name> 
     <timeout>10</timeout> 
     <points> 
      <point> 
       <a>5</a> 
       <b>7</b> 
       <c>11</c> 
      </point> 
      <point> 
       <a>8</a> 
       <b>7</b> 
       <c>3</c> 
      </point> 
     </points> 
    </Config> 

我試着尋找到XmlReaderSettings在ReadXml(XmlReader reader)與沒有幫助以下

var settings = new XmlReaderSettings 
{ 
    ValidationType = ValidationType.Schema, 
    Schemas = _schemaSet 
}; 

settings.ValidationEventHandler += (sender, args) => Console.WriteLine(args.Message); 
reader = XmlReader.Create(reader, settings); 

_schema從上面的靜態ConfigSchema()設置。

+0

請發表您的完整架構。另外,究竟是什麼問題?你說你可以反序列化,但是你認爲這是不正確的? –

+0

我不知道如何驗證將對該模式進行序列化的XML。 – clicky

+0

我編輯了你的標題。請參閱:「[應該在其標題中包含」標籤「](http://meta.stackexchange.com/questions/19190/)」,其中的共識是「不,他們不應該」。 –

回答

1

多挖後與幫助的形式休的答案,我能破解這個螺母。

  1. 我添加了命名空間我的XML和C#類:

    <?xml version="1.0" encoding="utf-8" ?> 
    <Config xlmns="namespace" ... 
    

    [XmlSchemaProvider("ConfigSchema")] 
    [XmlRoot(Namespace="namespace", ElementName="Config")] 
    public class Config : IXmlSerializable 
    { 
        private static XmlSchemaSet _schema; 
    
        public static XmlQualifiedName ConfigSchema(XmlSchemaSet xs) 
        { 
         _schema = xs; 
         // rest of method as OP 
        } 
    
        public void ReadXml(XmlReader reader) 
        { 
         var settings = new XmlReaderSettings 
         { 
         ValidationType = ValidationType.Schema, 
         Schemas = _schemas; 
         } 
    
         settings.ValidationEventHandler += ValidationCallBack; 
         reader = XmlReader.Create(reader, settings); 
         reader.Read(); // your own read logic 
        } 
    
        // rest of class 
    } 
    
  2. 我的XSD是完全錯誤的。我把類型定義與元素結構定義混淆了。

    <?xml version="1.0" encoding="utf-8"?> 
    <xs:schema id="ServiceConfigSchema" 
        targetNamespace="namespace" 
        elementFormDefault="qualified" 
        xmlns="namespace" 
        xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    
        <xs:complexType name="point"> 
        <xs:all> 
         <xs:element name="a" type="xs:int" /> 
         <xs:element name="b" type="xs:int" /> 
         <xs:element name="c" type="xs:int" /> 
        </xs:all> 
        </xs:complexType> 
    
        <xs:complexType name="points"> 
        <xs:sequence> 
         <xs:element name="point" type="point" minOccurs="1" maxOccurs="unbounded" /> 
        </xs:sequence> 
        </xs:complexType> 
    
        <xs:complexType name="Config"> 
        <xs:all> 
         <xs:element name="name" type="xs:string" /> 
         <xs:element name="timeout" type="xs:time" /> 
         <xs:element name="points" type="points" /> 
        </xs:all> 
        </xs:complexType> 
    
        <xs:element name="Config" type="Config" /> 
    </xs:schema> 
    
+0

我必須說,我發現它有點不規律,你基本上把我的答案整理成你自己的答案,然後授予你自己。上面的模式在語義上與我發佈的模式相同,與XML相同。當然,你需要使你的序列化代碼正常工作,但是這個特定的解決方案可能被表達爲對原始文章的修改,或者對我的評論。不太確定還有什麼要說的。 –

+0

您的回答非常有幫助,但它沒有解決問題,因爲它純粹是在查看XML(並且我在開始時提到了您的積極貢獻)。因爲我的問題不是如何爲我的XML編寫一個有效的模式,而是如何通過C#驗證它,所以需要更多的完整答案。無論如何,對於向自己炫耀任何東西都不感興趣,所以如果這讓你感覺更好,可以隨意取消標記或將其標記爲未標記。這個答案是我的問題的「完整解決方案」(就我的理解而言),因爲它涵蓋了XML,XSD和C#。 – clicky

4

XML未驗證,因爲您的模式指定了targetNamespace = "namespace",但您的XML實例未使用xmlns引用此名稱空間。

所以驗證器不知道如何驗證您的XML,因爲它沒有意識到您的XML使用您的模式中定義的類型。

如果您發佈您的完整模式和xml實例,我將能夠製作一個工作示例。

UPDATE

感謝張貼您的架構。你在哪裏得到它?我問的原因是它沒有定義任何根節點,只是一個名爲Config的類型。

如果去除外層複雜類型的元素:

<?xml version="1.0" encoding="utf-8"?> 
<xs:schema id="ConfigSchema" 
    targetNamespace="namespace" 
    elementFormDefault="qualified" 
    xmlns="namespace" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="Config"> 
    <xs:complexType> 
     <xs:all> 
     <xs:element name="name" type="xs:string" /> 
     <xs:element name="timeout" type="xs:time" /> 
     <xs:element name="points" minOccurs="1"> 
      <xs:complexType> 
      <xs:sequence> 
       <xs:element name="point" minOccurs="1" maxOccurs="unbounded"> 
       <xs:complexType> 
        <xs:all> 
        <xs:element name="a" type="xs:int" /> 
        <xs:element name="b" type="xs:int" /> 
        <xs:element name="c" type="xs:int" /> 
        </xs:all> 
       </xs:complexType> 
       </xs:element> 
      </xs:sequence> 
      </xs:complexType> 
     </xs:element> 
     </xs:all> 
    </xs:complexType> 
    </xs:element> 
</xs:schema> 

我能夠確認以下情況:

<?xml version="1.0" encoding="utf-8" ?> 
<Config xmlns="namespace"> 
    <name>some name</name> 
    <timeout>13:20:00.000-05:00</timeout> 
    <points> 
    <point> 
     <a>5</a> 
     <b>7</b> 
     <c>11</c> 
    </point> 
    <point> 
     <a>8</a> 
     <b>7</b> 
     <c>3</c> 
    </point> 
    </points> 
</Config> 

注意,「10」是不是超時列的有效值根據架構。當我嘗試,我得到這個錯誤:

The 'namespace:timeout' element is invalid - The value '10' is invalid according to its datatype ' http://www.w3.org/2001/XMLSchema:time ' - The string '10' is not a valid XsdDateTime value.

+0

謝謝,我用更多的信息更新了Q. – clicky

+0

我添加了'不是所期望的。「 – clicky

+0

看到我的更新.. –