2008-10-18 108 views
43

我有一個簡單的類,基本上只是持有一些值。我已經覆蓋了ToString()方法來返回一個漂亮的字符串表示。在沒有XmlDocument的情況下在C#中創建XmlNode/XmlElement?

現在,我想創建一個ToXml()方法,將返回這樣的事情:

<Song> 
    <Artist>Bla</Artist> 
    <Title>Foo</Title> 
</Song> 

當然,我可以在這裏使用一個StringBuilder,但我想返回XmlNodeXmlElement,與XmlDocument.AppendChild一起使用。

我似乎不能夠比調用XmlDocument.CreateElement創建一個XmlElement等,所以我不知道我剛纔忽略任何東西,或者如果我真的要麼在任何一個XmlDocumentref XmlElement一起工作通過,或有該函數返回一個包含我想要的XML的字符串?

+0

問題標題不符合提問內容/目標。你想知道如何序列化你的類。 我確實需要一個XmlNode實例來將它作爲webservice參數傳遞。用戶將從輸入字符串創建XmlNode。 – 2011-12-14 19:47:16

回答

13

您可能希望瞭解如何使用.NET的內置功能將對象序列化和反序列化爲XML,而不是在每個基本上只是數據傳輸對象的類上創建ToXML()方法。

我已經在幾個項目上成功地使用了這些技術,但現在還沒有實現細節。我會盡量用我自己的例子更新我的答案。

這裏有一對夫婦的例子,谷歌返回:由Venkat廉在.NET

XML序列化http://www.agiledeveloper.com/articles/XMLSerialization.pdf

如何序列化和反序列化對象到XML http://www.dotnetfunda.com/articles/article98.aspx

自定義您的.NET對象XML使用.NET XML屬性進行序列化http://blogs.microsoft.co.il/blogs/rotemb/archive/2008/07/27/customize-your-net-object-xml-serialization-with-net-xml-attributes.aspx

2

您需要Linq - System.Xml.Linq以確保準確。

您可以從頭開始使用XElement創建XML - 這應該會讓您感覺非常困難。

15

從W3C規範Document Object Model (Core) Level 1(粗體是礦):

大多數通過此 規範中定義的API都是接口而 不是類。這意味着一個 實際實現只需要暴露 方法與定義的名稱和 指定的操作,而不是實際上 實現對應 直接對接口的類。這個 允許將DOM API實施爲具有其自己的數據 結構的傳統 應用之上的薄單板,或者具有不同類 層級的較新的 應用之上。 這也意味着 普通構造(在Java或 C++意義上)不能被用於創建 DOM對象,因爲要構造底層 對象可以具有 到DOM 接口關係不大。傳統的解決方案 爲此在面向對象的設計中是 來定義工廠方法,該工廠方法創建實現各種接口的對象的實例 。在DOM 級別1中,實現一些 接口「X」的對象由 接口上的「createX()」方法創建; 這是因爲所有DOM 對象都生活在 特定文檔的上下文中。

AFAIK,你不能只是XmlDocument從構造函數創建任何XmlNodeXmlElement, XmlAttribute, XmlCDataSection等)。

此外,請注意,不能使用XmlDocument.AppendChild()作爲未通過相同文檔的工廠方法創建的節點。如果您有來自其他文檔的節點,則必須使用XmlDocument.ImportNode()

40

我會推薦使用XDoc和XElement的System.Xml.Linq而不是XmlDocument的東西。這將是更好,你就可以利用LINQ力量的查詢和解析您的XML:

使用的XElement,您toxml用於()方法如下所示:

public XElement ToXml() 
{ 
    XElement element = new XElement("Song", 
         new XElement("Artist", "bla"), 
         new XElement("Title", "Foo")); 

    return element; 
} 
1

您不能返回XmlElementXmlNode,因爲這些對象始終只存在於擁有XmlDocument的環境中。

XML序列化比返回XElement容易一些,因爲您只需標記具有屬性的屬性,並且序列化程序將爲您生成所有XML代。 (加上你可以免費獲得反序列化,假設你有一個無參數的構造函數,還有一堆其他的東西)。

另一方面,a)你必須創建一個XmlSerializer來做到這一點,b)處理集合屬性並不是你可能想要的那樣簡單,c)XML序列化非常愚蠢;如果您想對您生成的XML進行任何操作,那麼您運氣不佳。

在很多情況下,這些問題並不重要。我寧願用屬性來標記我的屬性,而不是寫一個方法。

4

你去你的班上了ToXML方法返回一個XmlDocument,那麼當你要與結果文檔添加的元素只是使用類似:

XmlDocument returnedDocument = Your_Class.ToXML(); 

XmlDocument finalDocument = new XmlDocument(); 
XmlElement createdElement = finalDocument.CreateElement("Desired_Element_Name"); 
createdElement.InnerXML = docResult.InnerXML; 
finalDocument.AppendChild(createdElement); 

這樣整個價值「Desired_Element_Name 「就你的結果而言,XmlDocument將成爲返回文檔的全部內容。

我希望這會有所幫助。

4

你想要的內容創建一個新的XmlDocument,然後將其導入到您現有的文檔,通過訪問你的現有節點的OwnerDocument屬性:

XmlNode existing_node; // of some document, where we don't know necessarily know the XmlDocument... 
XmlDocument temp = new XmlDocument(); 
temp.LoadXml("<new><elements/></new>"); 
XmlNode new_node = existing_node.OwnerDocument.ImportNode(temp.DocumentElement, true); 
existing_node.AppendChild(new_node); 

好運。

2

另一種選擇是將委託傳遞給方法,該方法將創建一個XmlElement。這樣,目標方法將無法訪問整個XmlDocument,但可以創建新的元素。

-2
XmlDocumnt xdoc = new XmlDocument; 
XmlNode songNode = xdoc.CreateNode(XmlNodeType.Element, "Song", schema) 
xdoc.AppendChild..... 
8

XmlNodes帶有OwnerDocument屬性。

也許你可以這樣做:

//Node is an XmlNode pulled from an XmlDocument 
XmlElement e = node.OwnerDocument.CreateElement("MyNewElement"); 
e.InnerText = "Some value"; 
node.AppendChild(e); 
2

爲什麼不考慮創建數據類(ES)只是一個子類XmlDocument的,那麼你得到的一切是免費的。您不需要序列化或創建任何非文檔節點,並且可以獲得所需的結構。

如果您想使它更復雜,請編寫一個基類,它是XmlDocument的子類,然後爲其提供基本訪問器,然後設置它。

這裏是一個通用型我放在一起爲一個項目...

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

namespace FWFWLib { 
    public abstract class ContainerDoc : XmlDocument { 

     protected XmlElement root = null; 
     protected const string XPATH_BASE = "/$DATA_TYPE$"; 
     protected const string XPATH_SINGLE_FIELD = "/$DATA_TYPE$/$FIELD_NAME$"; 

     protected const string DOC_DATE_FORMAT = "yyyyMMdd"; 
     protected const string DOC_TIME_FORMAT = "HHmmssfff"; 
     protected const string DOC_DATE_TIME_FORMAT = DOC_DATE_FORMAT + DOC_TIME_FORMAT; 

     protected readonly string datatypeName = "containerDoc"; 
     protected readonly string execid = System.Guid.NewGuid().ToString().Replace("-", ""); 

     #region startup and teardown 
     public ContainerDoc(string execid, string datatypeName) { 
      root = this.DocumentElement; 
      this.datatypeName = datatypeName; 
      this.execid = execid; 
      if(null == datatypeName || "" == datatypeName.Trim()) { 
       throw new InvalidDataException("Data type name can not be blank"); 
      } 
      Init(); 
     } 

     public ContainerDoc(string datatypeName) { 
      root = this.DocumentElement; 
      this.datatypeName = datatypeName; 
      if(null == datatypeName || "" == datatypeName.Trim()) { 
       throw new InvalidDataException("Data type name can not be blank"); 
      } 
      Init(); 
     } 

     private ContainerDoc() { /*...*/ } 

     protected virtual void Init() { 
      string basexpath = XPATH_BASE.Replace("$DATA_TYPE$", datatypeName); 
      root = (XmlElement)this.SelectSingleNode(basexpath); 
      if(null == root) { 
       root = this.CreateElement(datatypeName); 
       this.AppendChild(root); 
      } 
      SetFieldValue("createdate", DateTime.Now.ToString(DOC_DATE_FORMAT)); 
      SetFieldValue("createtime", DateTime.Now.ToString(DOC_TIME_FORMAT)); 
     } 
     #endregion 

     #region setting/getting data fields 
     public virtual void SetFieldValue(string fieldname, object val) { 
      if(null == fieldname || "" == fieldname.Trim()) { 
       return; 
      } 
      fieldname = fieldname.Replace(" ", "_").ToLower(); 
      string xpath = XPATH_SINGLE_FIELD.Replace("$FIELD_NAME$", fieldname).Replace("$DATA_TYPE$", datatypeName); 
      XmlNode node = this.SelectSingleNode(xpath); 
      if(null != node) { 
       if(null != val) { 
        node.InnerText = val.ToString(); 
       } 
      } else { 
       node = this.CreateElement(fieldname); 
       if(null != val) { 
        node.InnerText = val.ToString(); 
       } 
       root.AppendChild(node); 
      } 
     } 

     public virtual string FieldValue(string fieldname) { 
      if(null == fieldname) { 
       fieldname = ""; 
      } 
      fieldname = fieldname.ToLower().Trim(); 
      string rtn = ""; 
      XmlNode node = this.SelectSingleNode(XPATH_SINGLE_FIELD.Replace("$FIELD_NAME$", fieldname).Replace("$DATA_TYPE$", datatypeName)); 
      if(null != node) { 
       rtn = node.InnerText; 
      } 
      return rtn.Trim(); 
     } 

     public virtual string ToXml() { 
      return this.OuterXml; 
     } 

     public override string ToString() { 
      return ToXml(); 
     } 
     #endregion 

     #region io 
     public void WriteTo(string filename) { 
      TextWriter tw = new StreamWriter(filename); 
      tw.WriteLine(this.OuterXml); 
      tw.Close(); 
      tw.Dispose(); 
     } 

     public void WriteTo(Stream strm) { 
      TextWriter tw = new StreamWriter(strm); 
      tw.WriteLine(this.OuterXml); 
      tw.Close(); 
      tw.Dispose(); 
     } 

     public void WriteTo(TextWriter writer) { 
      writer.WriteLine(this.OuterXml); 
     } 
     #endregion 

    } 
}