November 15, 2010

XML結構描述定義(XSD)轉物件類別的方法(1) - 使用xsd.exe

在實作某些以XML為基礎的標準時,我們常會以XmlDocumentXmlWriter或.NET Framework3.5起支援的 XDocument類別來幫助我們產生符合的XML,通常一個well-defined的標準幾乎也都會附上其所參考的結構描述定義檔(*.xsd)

相較於使用XmlDocumentXmlWriterXDocument建立XML的方式,在實作較為大型的標準時,如果我們能以物件導向的方式將資料設定給某個物件後再將此物件序列化成XML,這樣的作法是否較為"美觀"也比較好維護/除錯。不過前提是,我們需要有一份(或以上)的XML結構描述定義檔。以下將分兩篇文章介紹兩種方法,可以將XSD轉換為物件類別

系統環境:Windows 7 x64, Visual Studio 2008
使用.NET Framework內建的xsd.exe工具(開啟Visual Studio 2008 命令提示字元)
xsd.exe工具詳細的用法可參考XML Schema Definition Tool (Xsd.exe)
利用此工具,我們可以一行command line就可以將XSD檔(參考http://msdn.microsoft.com/en-us/library/ms764613(VS.85).aspx)轉換出一支類別檔。
結構描述定義檔內容如下


  

  
    
      
      
  

  
    
      
      
      
      
      
      
    
    
  
執行以下指令

 /c指的是輸出類別檔 ,/o指的是輸出類別檔存放的位置。

產出的class如下
//------------------------------------------------------------------------------
// 
//     這段程式碼是由工具產生的。
//     執行階段版本:2.0.50727.4952
//
//     對這個檔案所做的變更可能會造成錯誤的行為,而且如果重新產生程式碼,
//     變更將會遺失。
// 
//------------------------------------------------------------------------------

using System.Xml.Serialization;

// 
// 此原始程式碼由 xsd 版本=2.0.50727.3038 自動產生。
// 


[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:books")]
[System.Xml.Serialization.XmlRootAttribute("books", Namespace="urn:books", IsNullable=false)]
public partial class BooksForm {
    
    private BookForm[] bookField;
    
    [System.Xml.Serialization.XmlElementAttribute("book", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public BookForm[] book {
        get {
            return this.bookField;
        }
        set {
            this.bookField = value;
        }
    }
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:books")]
public partial class BookForm {
    
    private string authorField;
    
    private string titleField;
    
    private string genreField;
    
    private float priceField;
    
    private System.DateTime pub_dateField;
    
    private string reviewField;
    
    private string idField;
    
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string author {
        get {
            return this.authorField;
        }
        set {
            this.authorField = value;
        }
    }
    
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string title {
        get {
            return this.titleField;
        }
        set {
            this.titleField = value;
        }
    }
    
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string genre {
        get {
            return this.genreField;
        }
        set {
            this.genreField = value;
        }
    }
    
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public float price {
        get {
            return this.priceField;
        }
        set {
            this.priceField = value;
        }
    }
    
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="date")]
    public System.DateTime pub_date {
        get {
            return this.pub_dateField;
        }
        set {
            this.pub_dateField = value;
        }
    }
    
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string review {
        get {
            return this.reviewField;
        }
        set {
            this.reviewField = value;
        }
    }
    
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string id {
        get {
            return this.idField;
        }
        set {
            this.idField = value;
        }
    }
}
 接下來我們即可以物件的方式來操作並透過XmlSerializer將物件序列化為XML,如下
            BooksForm bf = new BooksForm();

            BookForm[] bfArray = new BookForm[]
            {
                new BookForm(){ author = "Brad Abrams, Krzysztof Cwalina", title= "Framework Design Guidelines", price = 44.45F, pub_date = new DateTime(2008,11,1)},
                new BookForm(){ author = "Judith Bishop", title = "C# 3.0 Design Patterns", price = 26.39F, pub_date = new DateTime(2008,1,11)},
                new BookForm(){ author = "Dino Esposito, Andrea Saltarello", title = "Microsoft .NET Architecting Applications for the Enterprise (PRO-Developer)", price = 28.72F, pub_date = new DateTime(2008,12,23)}
            };

            bf.book = bfArray;
            XmlSerializer serializer = new XmlSerializer(bf.GetType());
            using (MemoryStream stream = new MemoryStream())
            {
                serializer.Serialize(stream, bf);
                Console.Write(Encoding.UTF8.GetString(stream.ToArray()));
            }
            
            Console.ReadKey(true);
最終產出的XML如下

備註
  1. 若要轉換的xsd還有參考到別的xsd檔,請記得一併加入指令中做處理
  2. 多個xsd一起做轉換時,若有互相參考或繼承,會有轉換順序的問題,請將基底的xsd放在最前依序排列做轉換,如xsd D:\base.xsd D:\derivedxsd1.xsd :D\derivedxsd2.xsd /c