在C#中创build一个XmlNode / XmlElement没有XmlDocument?

我有一个简单的类,基本上只是持有一些价值观。 我重写了ToString()方法返回一个不错的string表示。

现在,我想创build一个ToXml()方法,它将返回如下所示的内容:

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

当然,我可以在这里使用一个StringBuilder ,但是我想返回一个XmlNodeXmlElement ,与XmlDocument.AppendChild一起使用。

我似乎无法创build一个XmlElement而不是调用XmlDocument.CreateElement ,所以我不知道我是否忽略了任何东西,或者如果我真的要么传入一个XmlDocumentref XmlElement来处理,或者有函数返回一个包含我想要的XML的string?

您可能想要了解如何使用.NET的内置function将对象序列化和反序列化为XML,而不是在每个基本上只是数据传输对象的类上创buildToXML()方法。

我已经成功地在几个项目上使用了这些技术,但是现在还没有实现细节。 我会尽量用我自己的例子来更新我的答案。

以下是Google返回的一些示例:

在.NET中的XML序列化由Venkat Subramaniam articles/XMLSerialization.pdf

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

使用.NET XML属性自定义.NET对象XML序列化http://blogs.microsoft.com/zh-cn/kb/archive/2008/07/27/customize-your-net-object-xml-serialization-with-净XML的attributes.aspx

我build议使用XDoc和XElement的System.Xml.Linq而不是XmlDocument的东西。 这样做会更好,您将能够在查询和parsingXML时使用LINQ的强大function:

使用XElement,你的ToXml()方法如下所示:

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

从W3C 文档对象模型(核心)1级规范(粗体是我的):

本规范定义的大多数API都是接口而不是类。 这意味着一个实际的实现只需要暴露具有已定义名称和指定操作的方法,而不是实际实现与接口直接对应的类。 这使得DOM API可以作为传统应用程序自带数据结构的薄木板,或者在具有不同类层次结构的新应用程序之上实现。 这也意味着普通的构造函数(Java或C ++意义上的)不能用于创buildDOM对象,因为要构build的底层对象可能与DOM接口几乎没有关系 。 在面向对象的devise中,传统的解决scheme是定义创build实现各种接口的对象实例的工厂方法。 在DOM级别1中,实现某个接口“X”的对象由Document接口上的“createX()”方法创build; 这是因为所有DOM对象都生活在特定文档的上下文中

AFAIK,你不能从构造函数中创buildXmlNodeXmlElement, XmlAttribute, XmlCDataSection等),除了XmlDocument

此外,请注意,不能使用XmlDocument.AppendChild()作为未通过同一文档的工厂方法创build的节点。 如果您有来自另一个文档的节点,则必须使用XmlDocument.ImportNode()

XmlNodes带有OwnerDocument属性。

也许你可以做:

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

你可以在你的类中为ToXML方法返回一个XmlDocument ,然后当你要添加带有结果文档的Element时,只需使用如下所示的内容:

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

这样,结果XmlDocument上“Desired_Element_Name”的整个值就是返回Document的全部内容。

我希望这有帮助。

用你想要的内容创build一个新的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); 

祝你好运。

你需要Linq – System.Xml.Linq来做到精确。

你可以从头开始使用XElement来创buildXML,这应该会让你感到困惑。

另一种select是将委托传递给方法,该方法将创build一个XmlElement。 这样,目标方法将无法访问整个XmlDocument,但将能够创build新的元素。

为什么不考虑将数据类创build为子类XmlDocument,那么您可以免费获得所有这些。 您不需要序列化或创build任何非文档节点,并且可以获得所需的结构。

如果你想使它更复杂,写一个基类,它是XmlDocument的一个子类,然后给它基本的访问器,然后你就设置好了。

这是一个我为一个项目放在一起的通用types…

 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 } } 

您不能返回XmlElementXmlNode ,因为这些对象始终只存在于拥有XmlDocument的上下文中。

XML序列化比返回一个XElement容易一些,因为你所要做的就是标记带有属性的属性,序列化器为你做所有的XML生成。 (加上你可以免费获得反序列化,假设你有一个无参数的构造函数,以及其他一些东西。)

另一方面,a)你必须创build一个XmlSerializer来完成它,b)处理集合属性并不是你想要的那样简单,c)XML序列化非常愚蠢; 如果您想要对所生成的XML进行任何操作,那么您就不太好运了。

在很多情况下,这些问题并不重要。 我宁愿用属性来标记我的属性,而不是写一个方法。

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