Créer un XmlNode / XmlElement en C # sans XmlDocument?

J’ai une classe simple qui contient essentiellement des valeurs. J’ai remplacé la méthode ToSsortingng() pour renvoyer une belle représentation de chaîne.

Maintenant, je veux créer une méthode ToXml() , qui renverra quelque chose comme ceci:

  Bla Foo  

Bien sûr, je pourrais simplement utiliser un SsortingngBuilder ici, mais je voudrais retourner un XmlNode ou un XmlElement à utiliser avec XmlDocument.AppendChild .

Je ne semble pas être en mesure de créer un XmlElement autre que d’appeler XmlDocument.CreateElement , donc je me demande si je viens de négliger quelque chose, ou si je dois vraiment passer soit un XmlDocument ou ref XmlElement pour travailler avec, ou avoir le fonction retourne une chaîne qui contient le XML que je veux?

Vous voudrez peut-être examiner comment utiliser les fonctionnalités intégrées de .NET pour sérialiser et désérialiser un object en XML, plutôt que de créer une méthode ToXML() sur chaque classe qui est essentiellement un object de transfert de données.

J’ai utilisé ces techniques avec succès sur quelques projets mais je n’ai pas les détails de la mise en œuvre à scope de main dès maintenant. Je vais essayer de mettre à jour ma réponse avec mes propres exemples plus tard.

Voici quelques exemples renvoyés par Google:

Sérialisation XML en .NET par Venkat Subramaniam http://www.agiledeveloper.com/articles/XMLSerialization.pdf

Comment sérialiser et désérialiser un object en XML http://www.dotnetfunda.com/articles/article98.aspx

Personnalisez votre sérialisation XML d’object .NET avec les atsortingbuts XML .NET http://blogs.microsoft.co.il/blogs/rotemb/archive/2008/07/27/customize-your-net-object-xml-serialization-with- net-xml-atsortingbutes.aspx

Je recommande d’utiliser XDoc et XElement de System.Xml.Linq au lieu de XmlDocument. Ce serait mieux et vous pourrez utiliser le pouvoir LINQ pour interroger et parsingr votre XML:

En utilisant XElement, votre méthode ToXml () ressemblera à ceci:

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

D’après la spécification de niveau 1 du modèle d’object de document W3C (en gras est la mienne):

La plupart des API définies par cette spécification sont des interfaces plutôt que des classes. Cela signifie qu’une implémentation réelle n’a besoin que d’exposer des méthodes avec les noms définis et l’opération spécifiée, et non de mettre en œuvre des classes qui correspondent directement aux interfaces. Cela permet aux API DOM d’être implémentées en tant que placage fin au-dessus des applications héritées avec leurs propres structures de données, ou par-dessus les applications plus récentes avec différentes hiérarchies de classes. Cela signifie également que les constructeurs ordinaires (au sens Java ou C ++) ne peuvent pas être utilisés pour créer des objects DOM, car les objects sous-jacents à construire peuvent avoir peu de relation avec les interfaces DOM . La solution classique à ce problème dans la conception orientée object consiste à définir des méthodes d’usine qui créent des instances d’objects qui implémentent les différentes interfaces. Dans le DOM niveau 1, les objects implémentant une interface “X” sont créés par une méthode “createX ()” sur l’interface Document; C’est parce que tous les objects DOM vivent dans le contexte d’un document spécifique .

En fin de compte, vous ne pouvez créer aucun XmlNode ( XmlElement, XmlAtsortingbute, XmlCDataSection , etc.) sauf XmlDocument partir d’un constructeur.

De plus, notez que vous ne pouvez pas utiliser XmlDocument.AppendChild() pour les nœuds qui ne sont pas créés via les méthodes d’usine du même document. Si vous avez un noeud d’un autre document, vous devez utiliser XmlDocument.ImportNode() .

XmlNodes sont fournis avec une propriété OwnerDocument.

Peut-être que vous pouvez juste faire:

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

Vous pouvez retourner un XmlDocument pour la méthode ToXML dans votre classe, puis lorsque vous allez append l’élément avec le document de résultat, utilisez simplement quelque chose comme:

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

Ainsi, la valeur entière de “Desired_Element_Name” sur votre résultat XmlDocument sera la totalité du contenu du document renvoyé.

J’espère que ça aide.

Créez un nouveau XmlDocument avec le contenu souhaité, puis importez-le dans votre document existant en accédant à la propriété OwnerDocument de vos nœuds existants:

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

Bonne chance.

Vous avez besoin de Linq – System.Xml.Linq pour être précis.

Vous pouvez créer du code XML en utilisant XElement à partir de rien – cela devrait vous aider à le faire.

Une autre option consiste à transmettre un délégué à la méthode, ce qui créera un XmlElement. De cette façon, la méthode target n’aura pas access à l’intégralité de XmlDocument, mais pourra créer de nouveaux éléments.

Pourquoi ne pas envisager de créer vos classes de données en tant que XmlDocument sous-classé, alors vous obtenez tout cela gratuitement. Vous n’avez pas besoin de sérialiser ou de créer des nœuds hors-doc, et vous obtenez la structure souhaitée.

Si vous voulez le rendre plus sophistiqué, écrivez une classe de base qui est une sous-classe de XmlDocument, puis donnez-lui les accesseurs de base, et vous êtes défini.

Voici un type générique que j’ai mis en place pour un projet …

 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 ssortingng XPATH_BASE = "/$DATA_TYPE$"; protected const ssortingng XPATH_SINGLE_FIELD = "/$DATA_TYPE$/$FIELD_NAME$"; protected const ssortingng DOC_DATE_FORMAT = "yyyyMMdd"; protected const ssortingng DOC_TIME_FORMAT = "HHmmssfff"; protected const ssortingng DOC_DATE_TIME_FORMAT = DOC_DATE_FORMAT + DOC_TIME_FORMAT; protected readonly ssortingng datatypeName = "containerDoc"; protected readonly ssortingng execid = System.Guid.NewGuid().ToSsortingng().Replace( "-", "" ); #region startup and teardown public ContainerDoc( ssortingng execid, ssortingng 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( ssortingng 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() { ssortingng 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.ToSsortingng( DOC_DATE_FORMAT ) ); SetFieldValue( "createtime", DateTime.Now.ToSsortingng( DOC_TIME_FORMAT ) ); } #endregion #region setting/getting data fields public virtual void SetFieldValue( ssortingng fieldname, object val ) { if( null == fieldname || "" == fieldname.Trim() ) { return; } fieldname = fieldname.Replace( " ", "_" ).ToLower(); ssortingng 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.ToSsortingng(); } } else { node = this.CreateElement( fieldname ); if( null != val ) { node.InnerText = val.ToSsortingng(); } root.AppendChild( node ); } } public virtual ssortingng FieldValue( ssortingng fieldname ) { if( null == fieldname ) { fieldname = ""; } fieldname = fieldname.ToLower().Trim(); ssortingng 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 ssortingng ToXml() { return this.OuterXml; } public override ssortingng ToSsortingng() { return ToXml(); } #endregion #region io public void WriteTo( ssortingng 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 } } 

Vous ne pouvez pas retourner un XmlElement ou un XmlNode , car ces objects existent toujours et uniquement dans le contexte d’un XmlDocument propriétaire.

La sérialisation XML est un peu plus facile que de renvoyer un XElement , car il suffit de marquer les propriétés avec des atsortingbuts et le sérialiseur effectue toute la génération XML pour vous. (De plus, vous obtenez une désérialisation gratuite, en supposant que vous ayez un constructeur sans paramètre et, bien sûr, un tas d’autres choses.)

D’un autre côté, a) vous devez créer un XmlSerializer pour le faire, b) gérer les propriétés de la collection n’est pas une évidence, et c) la sérialisation XML est assez stupide; vous n’avez pas de chance si vous voulez faire quelque chose de compliqué avec le XML que vous générez.

Dans beaucoup de cas, ces problèmes sont sans importance. Pour ma part, je préfère marquer mes propriétés avec des atsortingbuts plutôt que d’écrire une méthode.

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