2008-10-18 14 views
43

Tôi có một lớp đơn giản về cơ bản chỉ giữ một số giá trị. Tôi đã ghi đè phương thức ToString() để trả về một biểu diễn chuỗi đẹp.Tạo một XmlNode/XmlElement trong C# mà không có một XmlDocument?

Bây giờ, tôi muốn tạo ra một phương pháp ToXml(), mà sẽ trở lại một cái gì đó như thế này:

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

Tất nhiên, tôi chỉ có thể sử dụng một StringBuilder ở đây, nhưng tôi muốn trả lại một XmlNode hoặc XmlElement, được sử dụng với XmlDocument.AppendChild.

Tôi dường như không có khả năng để tạo ra một khác XmlElement vì gọi XmlDocument.CreateElement, vì vậy tôi tự hỏi nếu tôi vừa bỏ qua bất cứ điều gì, hoặc nếu tôi thực sự có phải vượt qua trong hoặc là một XmlDocument hoặc ref XmlElement để làm việc với, hoặc có hàm trả về một String chứa XML mà tôi muốn?

+0

tiêu đề Câu hỏi đặt ra không tương ứng với câu hỏi nội dung/mục tiêu. Bạn muốn biết cách sắp xếp các lớp của bạn. Tôi cần một phiên bản của XmlNode để chuyển nó thành tham số webservice. Người dùng sẽ tạo XmlNode từ chuỗi đầu vào. –

+1

@DaviFiamenghi - Nhận xét của bạn không đúng. Nếu ai đó chọn xây dựng dữ liệu XML theo cách thủ công bằng cách sử dụng XmlNode, đó là lựa chọn của họ, có vẻ như không phải là cách để tạo các đối tượng XmlNode đó trong .Net mà không tạo nó từ một XmlDocument. – antiduh

Trả lời

13

Bạn có thể muốn xem xét cách bạn có thể sử dụng các tính năng dựng sẵn của .NET để tuần tự hóa và deserialize một đối tượng thành XML, thay vì tạo một phương thức ToXML() trên mọi lớp về cơ bản chỉ là một đối tượng truyền dữ liệu.

Tôi đã sử dụng các kỹ thuật này thành công trên một vài dự án nhưng hiện không có các chi tiết triển khai hữu ích. Tôi sẽ cố gắng cập nhật câu trả lời của mình với các ví dụ của riêng tôi sau này.

Dưới đây là một vài ví dụ mà Google trả về: serialization

XML trong .NET bởi Venkat Subramaniam http://www.agiledeveloper.com/articles/XMLSerialization.pdf

Làm thế nào để Serialize và Deserialize một đối tượng vào XML http://www.dotnetfunda.com/articles/article98.aspx

Customize NET đối tượng XML của bạn tuần tự hóa với các thuộc tính .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

Bạn cần LINQ - System.Xml.Linq chính xác.

Bạn có thể tạo XML bằng cách sử dụng XElement từ đầu - bạn nên sắp xếp khá nhiều.

15

Từ W3C Document Object Model (Core) Level 1 đặc điểm kỹ thuật (đậm là của tôi):

Hầu hết các API định nghĩa bởi đặc điểm kỹ thuật này là giao diện khá hơn các lớp học. Điều đó có nghĩa là chỉ cần nhu cầu triển khai thực tế chỉ hiển thị các phương thức có tên được xác định và hoạt động được chỉ định, không thực sự triển khai các lớp tương ứng với trực tiếp vào giao diện. này cho phép các API DOM được triển khai dưới dạng veneer mỏng ở trên các ứng dụng cũ với dữ liệu riêng của chúng cấu trúc hoặc trên các ứng dụng mới hơn với các lớp khác nhau . này cũng có nghĩa là nhà xây dựng thông thường (trong Java hay C++ cảm giác) không thể được sử dụng để tạo đối tượng DOM, kể từ khi cơ bản đối tượng được xây dựng có thể có mối quan hệ chút vào DOM giao diện. Các giải pháp thông thường để điều này trong thiết kế hướng đối tượng là để xác định phương pháp nhà máy tạo ra trường hợp của các đối tượng thực hiện các giao diện khác nhau. Trong DOM Cấp 1, các đối tượng triển khai một số giao diện "X" được tạo bởi phương thức "createX()" trên giao diện Tài liệu ; điều này là do tất cả các đối tượng DOM đều sống trong ngữ cảnh của Tài liệu cụ thể.

AFAIK, bạn không thể tạo ra bất kỳ XmlNode (XmlElement, XmlAttribute, XmlCDataSection, vv) trừ XmlDocument từ một constructor.

Ngoài ra, lưu ý rằng bạn không thể sử dụng XmlDocument.AppendChild() cho các nút không được tạo thông qua các phương pháp nhà máy của cùng một tài liệu. Trong trường hợp bạn có một nút từ một tài liệu khác, bạn phải sử dụng XmlDocument.ImportNode().

40

Tôi khuyên bạn nên sử dụng XDoc và XElement của System.Xml.Linq thay vì công cụ XmlDocument. Đây sẽ là tốt hơn và bạn sẽ có thể tận dụng sức mạnh LINQ trong truy vấn và phân tích cú pháp XML của bạn:

Sử dụng XElement, ToXml của bạn() phương pháp sẽ trông giống như sau:

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

    return element; 
} 
1

Bạn không thể trả lại XmlElement hoặc XmlNode, bởi vì những đối tượng đó luôn luôn và chỉ tồn tại trong bối cảnh sở hữu XmlDocument.

Việc tuần tự hóa XML dễ dàng hơn một chút so với trả về XElement, bởi vì tất cả những gì bạn phải làm là đánh dấu các thuộc tính với các thuộc tính và bộ nối tiếp thực hiện tất cả các thế hệ XML cho bạn. (Ngoài ra bạn có được deserialization miễn phí, giả sử bạn có một constructor parameterless và, tốt, một loạt các thứ khác.)

Mặt khác, a) bạn phải tạo một XmlSerializer để làm điều đó, b) xử lý thuộc tính bộ sưu tập không hoàn toàn là không có trí tuệ bạn có thể thích nó, và c) XML serialization là khá ngu ngốc; bạn không may mắn nếu bạn muốn làm bất cứ điều gì ưa thích với XML bạn đang tạo ra.

Trong nhiều trường hợp, những vấn đề đó không quan trọng một chút. Tôi cho một thay vì sẽ đánh dấu tài sản của tôi với các thuộc tính hơn là viết một phương pháp.

4

Bạn có thể trả về một XmlDocument cho phương pháp ToXML trong lớp học của bạn, sau đó khi bạn đang đi để thêm phần tử với tài liệu kết quả chỉ cần sử dụng một cái gì đó như:

XmlDocument returnedDocument = Your_Class.ToXML(); 

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

Bằng cách đó toàn bộ giá trị cho "Desired_Element_Name "trên kết quả của bạn XmlDocument sẽ là toàn bộ nội dung của Tài liệu được trả về.

Tôi hy vọng điều này sẽ hữu ích.

4

Tạo một XmlDocument mới với những nội dung mà bạn muốn và sau đó nhập nó vào tài liệu hiện tại của bạn, bằng cách truy cập các tài sản OwnerDocument của nút hiện tại của bạn:

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); 

Chúc may mắn.

2

Một tùy chọn khác là chuyển một đại biểu đến phương thức, điều này sẽ tạo một XmlElement. Bằng cách này, phương pháp đích sẽ không nhận được quyền truy cập vào toàn bộ XmlDocument, nhưng sẽ có thể tạo ra các phần tử mới.

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

XmlNodes đi kèm với thuộc tính OwnerDocument.

Có lẽ bạn chỉ có thể làm:

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

Tại sao không xem xét việc tạo lớp dữ liệu của bạn (es) như chỉ là một XmlDocument subclassed, sau đó bạn sẽ có được tất cả điều đó miễn phí. Bạn không cần serialize hoặc tạo ra bất kỳ nút off-doc nào cả, và bạn nhận được cấu trúc mà bạn muốn.

Nếu bạn muốn làm cho nó tinh vi hơn, hãy viết một lớp cơ sở là một lớp con của XmlDocument, sau đó cung cấp cho nó các trình truy cập cơ bản và bạn được thiết lập.

Dưới đây là một kiểu generic tôi đặt lại với nhau cho một dự án ...

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 

    } 
} 
Các vấn đề liên quan