2013-04-04 22 views
11

我使用XmlSerializer創建表示XML文件的對象,現在我想向我的xml文件的rootelement添加一個schemalocation。 我可以添加命名空間像下面如何將xsi schemalocation添加到根目錄c#對象XmlSerializer

 XmlSerializer serializer = new XmlSerializer(typeof(MyClass)); 
     System.IO.FileStream fs = new FileStream(@"C:\test.xml", FileMode.Create); 
     TextWriter writer = new StreamWriter(fs, new UTF8Encoding()); 

     XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 
     ns.Add("xy","http://www.w3.org/2005/08/addressing"); 
     ns.Add("xlink","http://www.w3.org/1999/xlink"); 
     serializer.Serialize(writer, myObject, ns); 

但我怎麼我的C#代碼中添加xsi:schemalocation屬性,我的根元素。命名空間增加了一個簡單的ns.Add()。我想避免與xsd.exe生成的c#類混淆。 或者我必須手動編輯生成的c#類,並添加一些屬性到我的xml的根元素?

編輯:我看過例子,我需要手動編輯我的c#,但必須有一種方法在代碼中做到這一點!如果我們能夠向我們的根元素添加命名空間,爲什麼不能添加schemalocations?

+1

相關或重複:[XmlSerialization和xsi:SchemaLocation(xsd.exe)](https://stackoverflow.com/questions/1408336/xmlserialization-and-xsischemalocation-xsd-exe) – dbc 2016-03-15 16:29:20

回答

9

假設以下XSD:

<?xml version="1.0" encoding="utf-8" ?> 
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) --> 
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" xmlns="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <xsd:element name="elementB"> 
     <xsd:complexType> 
      <xsd:sequence> 
       <xsd:element name="FirstName" type="xsd:string"/> 
       <xsd:element name="LastName" type="xsd:string"/> 
      </xsd:sequence> 
     </xsd:complexType> 
    </xsd:element> 
</xsd:schema> 

有兩種方法至少做到這一點。第一個依賴於繼承以及如何使用序列化器註釋。

XSD.EXE生成此:

//------------------------------------------------------------------------------ 
// <auto-generated> 
//  This code was generated by a tool. 
//  Runtime Version:4.0.30319.18034 
// 
//  Changes to this file may cause incorrect behavior and will be lost if 
//  the code is regenerated. 
// </auto-generated> 
//------------------------------------------------------------------------------ 

using System.Xml.Serialization; 

// 
// This source code was auto-generated by xsd, Version=4.0.30319.1. 
// 

/// <remarks/> 
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")] 
[System.SerializableAttribute()] 
[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.ComponentModel.DesignerCategoryAttribute("code")] 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://tempuri.org/XMLSchema.xsd")] 
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://tempuri.org/XMLSchema.xsd", IsNullable=false)] 
public partial class elementB { 

    private string firstNameField; 

    private string lastNameField; 

    /// <remarks/> 
    public string FirstName { 
     get { 
      return this.firstNameField; 
     } 
     set { 
      this.firstNameField = value; 
     } 
    } 

    /// <remarks/> 
    public string LastName { 
     get { 
      return this.lastNameField; 
     } 
     set { 
      this.lastNameField = value; 
     } 
    } 
} 

「注入」 的xsi:schemaLocation添加一個新類,elementA : elementB;聲明:

  • System.Xml.Serialization.XmlRootAttribute設置
  • schemaLocation屬性設置。

測試程序:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Xml.Serialization; 
using System.IO; 
using System.Xml; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      elementB b = new elementB(); 
      b.FirstName = "P"; 
      b.LastName = "G"; 

      XmlSerializer ser = new XmlSerializer(typeof(elementB)); 
      StringBuilder sb = new StringBuilder(); 
      using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true })) 
      { 
       ser.Serialize(writer, b); 
      } 
      Console.WriteLine(sb.ToString()); 

      elementA a = new elementA(); 
      a.FirstName = "P"; 
      a.LastName = "G"; 
      a.schemaLocation = "http://tempuri.org/XMLSchema.xsd me"; 
      ser = new XmlSerializer(typeof(elementA)); 
      sb = new StringBuilder(); 
      using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true })) 
      { 
       ser.Serialize(writer, a); 
      } 
      Console.WriteLine(sb.ToString()); 
     } 
    } 
} 

[System.SerializableAttribute()] 
[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.ComponentModel.DesignerCategoryAttribute("code")] 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/XMLSchema.xsd")] 
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/XMLSchema.xsd", ElementName = "elementB", IsNullable = false)] 
public partial class elementA : elementB 
{ 

    private string torefField; 

    /// <remarks/> 
    [System.Xml.Serialization.XmlAttributeAttribute(Form = System.Xml.Schema.XmlSchemaForm.Qualified, Namespace = "http://www.w3.org/2001/XMLSchema-instance")] 
    public string schemaLocation 
    { 
     get 
     { 
      return this.torefField; 
     } 
     set 
     { 
      this.torefField = value; 
     } 
    } 
} 

產生預期的結果:

<?xml version="1.0" encoding="utf-16"?> 
<elementB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/XMLSchema.xsd"> 
    <FirstName>P</FirstName> 
    <LastName>G</LastName> 
</elementB> 
<?xml version="1.0" encoding="utf-16"?> 
<elementB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://tempuri.org/XMLSchema.xsd me" xmlns="http://tempuri.org/XMLSchema.xsd"> 
    <FirstName>Petru</FirstName> 
    <LastName>Gardea</LastName> 
</elementB> 

第二種方法依賴於定製寫入,將注入你想要什麼,你需要的地方(假設適當的邏輯)。

實現一個自定義的XmlWriter:

class MyXmlWriter : XmlWriter 
{ 
    XmlWriter _writer; 
    bool _docElement = true; 

    public string SchemaLocation { get; set; } 
    public string NoNamespaceSchemaLocation { get; set; } 

    public MyXmlWriter(XmlWriter writer) 
    { 
     _writer = writer; 
    } 

    (other methods omitted) 

    public override void WriteStartElement(string prefix, string localName, string ns) 
    { 
     _writer.WriteStartElement(prefix, localName, ns); 
     if (_docElement) 
     { 
      if (!string.IsNullOrEmpty(SchemaLocation)) 
      { 
       _writer.WriteAttributeString("xsi", "schemaLocation", "http://www.w3.org/2001/XMLSchema-instance", SchemaLocation); 
      } 
      if (!string.IsNullOrEmpty(NoNamespaceSchemaLocation)) 
      { 
       _writer.WriteAttributeString("xsi", "noNamesapceSchemaLocation", "http://www.w3.org/2001/XMLSchema-instance", NoNamespaceSchemaLocation); 
      } 
      _docElement = false; 
     } 
    } 

    (other methods omitted) 

} 

一種改進的測試程序:

static void Main(string[] args) 
{ 
    elementB b = new elementB(); 
    b.FirstName = "P"; 
    b.LastName = "G"; 

    XmlSerializer ser = new XmlSerializer(typeof(elementB)); 
    StringBuilder sb = new StringBuilder(); 
    using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true })) 
    { 
     ser.Serialize(writer, b); 
    } 
    Console.WriteLine(sb.ToString()); 

    sb = new StringBuilder(); 

    using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true })) 
    { 
     MyXmlWriter newWriter = new MyXmlWriter(writer) { SchemaLocation = "http://tempuri.org/XMLSchema.xsd me" }; 
     ser.Serialize(newWriter, b); 
    } 
    Console.WriteLine(sb.ToString()); 
} 

的結果是一樣的...

<?xml version="1.0" encoding="utf-16"?> 
<elementB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/XMLSchema.xsd"> 
    <FirstName>P</FirstName> 
    <LastName>G</LastName> 
</elementB> 
<?xml version="1.0" encoding="utf-16"?> 
<elementB xsi:schemaLocation="http://tempuri.org/XMLSchema.xsd me" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd"> 
    <FirstName>P</FirstName> 
    <LastName>G</LastName> 
</elementB> 
+0

thx您的帖子。在自己的源代碼中擴展根類看起來非常有趣。我會在一些實際的經驗後回來。 – Gero 2013-04-12 11:10:36

13

的XSD.EXE產生子類,所以你可以添加你自己的單獨的部分類來保存xsi:schemaLocation等字段或屬性。

因此,增加@Petru Gardea的樣品elementB類,你只需要在項目中創建另一個文件,並添加此部分類:

public partial class elementB 
{ 
    [XmlAttributeAttribute("schemaLocation", Namespace="http://www.w3.org/2001/XMLSchema-instance")] 
    public string xsiSchemaLocation = "http://www.acme.com/xml/OrderXML-1-0.xsd"; 
} 

有一個疑難雜症,我遇到了這樣做的,這默認情況下,xsd.exe不會將名稱空間添加到生成的文件中。當你創建你自己的這個部分類時,它很可能在命名空間中。由於< 默認命名空間>和顯式定義的命名空間不匹配,部分將不起作用。因此,您需要使用xsd.exe上的命名空間選項來將生成的類實際獲取到命名空間中。

+0

嗨,你是什麼意思「需要使用xsd.exe上的命名空間選項來實際獲得生成的類到你的命名空間」? – 2016-05-26 16:06:08

+1

@CiaranGallagher在xsd.exe命令行上,它有一個名爲/ namespace的開關:這會將生成的類包裝在該名稱空間中 – ToddK 2016-06-09 15:48:45