2008-10-18 107 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 

    } 
}