2012-02-06 37 views
5

Tôi đang sử dụng XmlSerializer. Lớp học của tôi:XmlSerializer: tuần tự hóa thuộc tính lớp dưới dạng thuộc tính của một subelement tùy chỉnh

[Serializable] 
[XmlRoot(ElementName="MyClass")] 
public class MyClass 
{ 
    public string Value; 
} 

Tôi muốn serialize nó để Value kết thúc như là một thuộc tính của một subelement tên (ví dụ) "Văn bản".

kết quả mong muốn:

<MyClass> 
    <Text Value="3"/> 
</MyClass> 

Nhưng KHÔNG (đó sẽ là ảnh hưởng của giá trị gia tăng đánh dấu như một XmlAttribute)

<MyClass Value="3"> 
</MyClass> 

KHÔNG (mà sẽ là hiệu quả đánh dấu Giá trị là XmlElement):

<MyClass> 
    <Value>3</Value> 
</MyClass> 

Làm cách nào để đạt được điều này?

Tôi biết rằng tôi có thể thay đổi loại Value từ chuỗi thành một lớp tùy chỉnh tuần tự khác.

Thật không may, tôi có nhiều thuộc tính như vậy, vì vậy tôi cần tạo hàng tá lớp học nhỏ.

Có giải pháp nào nhanh hơn không?


EDIT:

Đáp lại ý kiến ​​của bạn:

  • Không, không phải mọi tài sản phải được đăng một subelement tên "Text". Tên của danh sách con là duy nhất và không rõ ràng.

  • Mẫu đầu ra XML:

    <visibility> 
        <site visible="yes"/> 
        <comparator visible="no"/> 
        <expiration days="7"/> 
        <comment>blahblahblah</comment> 
    <visibility> 
    
  • mẫu lớp:

!

[XmlRoot(ElementName="Visibility")] 
public class Visibility 
{ 
    [XPath("/[email protected]")] // if only this was possible! 
    public string OnSite 
    { 
     get { return SiteVisible ? "yes" : "no"; } 
    } 

    [XPath("/[email protected]")] // as above... 
    public string InComparator 
    { 
     get { return ComparatorVisible ? "yes" : "no"; } 
    } 

    [XmlIgnore] 
    public bool SiteVisible; 
    [XmlIgnore] 
    public bool ComparatorVisible; 

    [XPath("/[email protected]")] // as above... 
    public int ExpiresAfterDays; 

    [XmlElement("comment")] // this is easy 
    public string Comment; 
} 
+1

Bạn có thể cung cấp đầy đủ cấu trúc XML mong muốn (3-5 phần tử/thuộc tính) với lớp thích hợp không? –

+0

Tôi đã có một giải pháp cho điều này - nhưng không phải nếu mọi tài sản cần phải tuần tự hóa thành một phần tử có tên là "Văn bản" - vì vậy bạn sẽ cần cung cấp thêm ví dụ, theo yêu cầu của Kirill. Vấn đề với việc có nhiều hơn một "văn bản" là nó sẽ không thể deserialize theo hướng ngược lại như serializer sẽ không thể xác định tài sản mà mỗi "văn bản" bản đồ đến. Xin vui lòng cho nhiều hơn, vì vậy chúng tôi có thể giúp đỡ. –

+1

như là một sang một bên - Tôi nghi ngờ bạn có nghĩa là [XmlIgnore] thay vì [NonSerialized]. –

Trả lời

4

Không thay đổi loại Value Tôi nghĩ điều đó là không thể. Bạn có thể thêm các thuộc tính XmlElement(ElementName="Text") trên Value nhưng bạn sẽ có được một kết quả tương tự như sau:

<MyClass> 
    <Text>3</Text> 
</MyClass> 

được sửa đổi: Một giải pháp khác có thể liên quan đến việc chuyển đổi XSLT: bạn có thể tạo xml sử dụng Net serialization và sau khi áp dụng một xml chuyển đổi.

XslTransform myXslTransform = new XslTransform(); 
myXslTransform.Load(xsltDoc); 
myXslTransform.Transform(sourceDoc, resultDoc); 

Các trasformation của ví dụ của tôi nên một cái gì đó như thế này:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/"> 
    <root> 
     <xsl:apply-templates/> 
    </root> 
    </xsl:template> 
    <xsl:template match="MyClass"> 
     <MyClass> 
      <Text> 
       <xsl:attribute name="Value"> 
        <xsl:value-of select="Text"/> 
       </xsl:attribute> 
      </Text> 
     </MyClass> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Đó là một biến thể tốt đẹp về ý tưởng của tôi về việc thực hiện chuyển đổi trên kết quả XML, vì nó liên quan đến chức năng tồn tại trước (XSLT). Một thuộc tính tùy chỉnh cộng với một lớp tạo XSLT đầy đủ trên bay sẽ là một sự tăng cường tuyệt vời các khả năng tuần tự hóa XML của .NET, tôi tưởng tượng –

4

Đối với loại này linh hoạt, bạn thực sự nên suy nghĩ về việc thực hiện IXmlSerializable vì điều này mang đến cho bạn kiểm soát nhiều hơn nữa:

[XmlRoot("visibility")] 
public class Visibility : IXmlSerializable 
{ 
    public string Site; 
    public string Comparator; 
    public int Expiration; 
    public string Comment; 

    public XmlSchema GetSchema() 
    { 
     throw new NotImplementedException(); 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     // implement me if you want to deserialize too. 
     throw new NotImplementedException(); 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     WriteProperty(writer, "site", "visible", Site); 
     WriteProperty(writer, "comparator ", "visible", Comparator); 
     WriteProperty(writer, "expiration ", "days", Expiration); 

     if (!string.IsNullOrEmpty(Comment)) 
     { 
      writer.WriteElementString("comment", Comment); 
     } 
    } 

    private void WriteProperty<T>(XmlWriter writer, string elementName, string attibuteName, T value) 
    { 
     if (value != null) 
     { 
      writer.WriteStartElement(elementName); 
      writer.WriteAttributeString(attibuteName, value.ToString()); 
      writer.WriteEndElement(); 
     } 
    } 
} 

Rõ ràng, có một chút công việc thủ công ở đây, nhưng nó cho phép bạn giữ tất cả các mã tuần tự ở một nơi, thay vì có sự gia tăng của cla nhỏ hơn sses.

Ví dụ trên chỉ thực hiện tuần tự hóa - bạn cần viết một triển khai deserialize tương đương nếu bạn cần deserialize từ xml đến loại của bạn.

+0

+1 Không tệ, mặc dù tôi hy vọng một cái gì đó chung chung hơn. –

+1

Tôi đã chơi xung quanh với một lớp tùy chỉnh cho các thuộc tính, PropertyXmlFormatter .Sau đó, bạn sẽ làm cho mỗi thuộc tính là PropertyXmlFormatter thay vì chuỗi, v.v. Nó có một toán tử ẩn ngầm ẩn và .Equals để nó có thể được sử dụng làm kiểu thực trong phép gán và so sánh. Vấn đề là, nó đã kết thúc quá nhiều công việc để làm cho nó đáng giá. –

0

Cảm ơn tất cả các câu trả lời. Thật đáng tiếc là thư viện .NET XmlSerialization không cho phép điều đó (tôi nghĩ nó nên!). Tôi đang tìm một giải pháp chung chung nhất có thể.

Điều tốt nhất tôi có thể đưa ra (tốt nhất xem xét các tiêu chí về tính tổng thể tối đa, trong khi thực hiện nhanh chóng một cách hợp lý) là cho phép sắp xếp từng lớp theo cách của nó, sau đó chỉ chuyển đổi đầu ra, di chuyển các phần tử nhất định vào các vị trí lồng nhau.

Something như thế:

/// <remarks> 
    /// (angle brackets replaced with round ones to avoid confusing the XML-based documentation comments format) 
    /// 
    /// Let input XML be: 
    /// 
    ///  (root) 
    ///   (days)3(/days) 
    ///  (/root) 
    ///  
    /// Calling Reposition on this input with mappings argument being: 
    ///  (key) "days" 
    ///  (value) { "time", "days" } 
    ///  
    /// Returns: 
    /// (root) 
    ///  (time days="3" /) 
    /// (/root) 
    /// </remarks>   
    static XElement Reposition(XElement input, KeyValuePair<string, string[]>[] mappings) 
    { 
     var result = new XElement(input); 
     foreach (var mapping in mappings) 
     { 
      var element = result.Element(mapping.Key); 
      if (element == null) 
      { 
       continue; 
      } 
      var value = element.Value; 
      element.Remove(); 

      var insertAt = result; 
      foreach (var breadcrumb in mapping.Value) 
      { 
       if (breadcrumb == mapping.Value.Last()) 
       { 
        insertAt.Add(new XAttribute(breadcrumb, value)); 
       } 
       else 
       { 
        insertAt.Add(new XElement(breadcrumb)); 
        insertAt = insertAt.Element(breadcrumb); 
       } 
      } 
     } 
     return result; 
    } 

Tôi nghĩ rằng tôi sẽ kết hợp nó với một thuộc tính tùy chỉnh (loại tương tự như thuộc tính XPath mà tôi mong sẽ tồn tại: xem mã mẫu trong câu hỏi của tôi), và quấn lại chức năng này trong một lớp serializer của riêng tôi.

Mọi nhận xét/thông tin chi tiết về cách tiếp cận này?

Tôi có thể nghĩ về một nhược điểm hiệu suất tiềm năng (viết lại/reparsing XML sau mỗi serialization), nhưng các phần kết quả của XML không được dự kiến ​​sẽ có kích thước lớn, vì vậy điều này có lẽ không đáng kể.

Câu hỏi về deserialization không làm phiền tôi vào thời điểm này (deserialization đã được thực hiện và được thực hiện khá "thủ công", bởi XPath và một số phương pháp tiện ích).

+1

Bạn có thể xem xét sử dụng XSLT để chuyển đổi xml được tạo bởi .Net trong XML cần cho trao đổi dữ liệu của bạn. –

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