2015-10-02 13 views
10

Tôi có một loạt các lớp C#, được tạo tự động từ một XSD. Sau đó, tôi tạo các tệp XML dựa trên các lớp C# đó. Hiện không có nội dung nào.Tôi có thể có thuộc tính null và thuộc tính khác tại cùng một thẻ trong XML được tạo bởi lớp XSD C# được tạo không?

Vấn đề:

Các tập tin XML được tạo ra đang trải qua xác nhận và xác nhận yêu cầu một thuộc tính thêm vào tất cả các thẻ XML với xsi:nil="true". Về cơ bản các thẻ sẽ giống như: <testTag.01 xsi:nil="true" NV="123123" />, nhưng tôi không thể đạt được điều đó trong C#. Mã của tôi là:

 if (myObject.TestTag.HasValue) 
     { 
      t.testTag01 = new testTag01(); 
      t.testTag01.Value = myObject.TestTag.Value; 
     } 
     //else 
     //{ 
     // t.testTag01 = new testTag01(); 
     // t.testTag01.NV = "123123";//Not Recorded 
     //} 

Mã này tạo <testTag.01>SomeValue</testTag.01> hoặc <testTag.01 xsi:nil="true"/>.

Nếu tôi bỏ ghi chú ELSE, kết quả sẽ là: <testTag.01>SomeValue</testTag.01> hoặc <testTag.01 NV="123123" />.

Vì vậy, tôi không có ý tưởng làm thế nào để có được định dạng, được yêu cầu bởi công cụ xác nhận. Bất kỳ ý tưởng?

P.S.

Đây là tính năng tự động tạo ra C# lớp:

/// [System.CodeDom.Compiler.GeneratedCodeAttribute ("xsd", "4.0.30319.33440")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute ("code")] [System.Xml.Serialization.XmlTypeAttribute (AnonymousType = true, Namespace = "http://www.blabla.org ")]

lớp công khai một phần testTag01 {

private string nvField; 

private SomeEnum valueField; 

/// <remarks/> 
[System.Xml.Serialization.XmlAttributeAttribute()] 
public string NV { 
    get { 
     return this.nvField; 
    } 
    set { 
     this.nvField = value; 
    } 
} 

/// <remarks/> 
[System.Xml.Serialization.XmlTextAttribute()] 
public SomeEnum Value { 
    get { 
     return this.valueField; 
    } 
    set { 
     this.valueField = value; 
    } 
} } 

Tôi không muốn thay đổi phần đó, nhưng tôi hiểu điều đó là không thể nếu không thực hiện. Ngoài ra tôi đã cố gắng để thiết lập SomeEnum là Nullable. public SomeEnum? Value, nhưng là ném một ngoại lệ:

Cannot serialize member 'Value' of type System.Nullable`1[]. XmlAttribute/XmlText cannot be used to encode complex types. 
+0

Cần xem các lớp được tạo tự động. Những thứ này thường cần được chỉnh sửa. Bạn không cần phải thêm mã để tạo ra các giá trị rỗng. – jdweng

+0

Tôi đã xếp lớp. Ngoài ra tôi đã cố gắng thiết lập giá trị để Nullable, nhưng nó là ném một ngoại lệ. :-( – Tech0

+1

Thao tác này sẽ không hoạt động. Hãy xem [** Xsi: nil Hỗ trợ ràng buộc thuộc tính **: Thuộc tính nil và các thuộc tính khác] (https://msdn.microsoft.com/en-us/library/ ybce7f69.aspx) – dbc

Trả lời

1

XmlSerializer không trực tiếp hỗ trợ gắn vào các yếu tố đồng thời có xsi:nil="true" cùng với giá trị thuộc tính khác; xem Xsi:nil Attribute Binding Support: The nil attribute and other attributes.

Vì vậy, bạn cần phải phát ra thuộc tính theo cách thủ công.

Nếu bạn muốn để có thể tạo ra một yếu tố không có nội dung và hai thuộc tính, một trong những tên NV và khác luônxsi:nil="true", bạn có thể thay đổi lớp testTag01 của bạn để có NV bất động sản cũng như một tài sản tổng hợp có không gian tên chính xác và tên:

public class testTag01 
{ 
    [XmlAttribute] 
    public string NV { get; set; } 

    [XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")] 
    public string Nil { get { return "true"; } set { } } 
} 

Nếu bạn đôi khi muốn có xsi:nil="true" nhưng vào những thời điểm khác muốn phần tử có nội dung tương ứng với SomeEnum của bạn, bạn cần phải làm điều gì đó một bi t phức tạp hơn, kể từ khi xsi:nil="true" phải bị dập tắt khi nguyên tố này có nội dung:

public class testTag01 
{ 
    [XmlAttribute] 
    public string NV { get; set; } 

    [XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")] 
    public string Nil { get { return SomeEnum == null ? "true" : null; } set { } } 

    public bool ShouldSerializeNil() { return SomeEnum == null; } 

    [XmlIgnore] 
    public SomeEnum? SomeEnum { get; set; } 

    [XmlText] 
    public string SomeEnumText 
    { 
     get 
     { 
      if (SomeEnum == null) 
       return null; 
      return SomeEnum.Value.ToString(); 
     } 
     set 
     { 
      // See here if one needs to parse XmlEnumAttribute attributes 
      // http://stackoverflow.com/questions/3047125/retrieve-enum-value-based-on-xmlenumattribute-name-value 
      value = value.Trim(); 
      if (string.IsNullOrEmpty(value)) 
       SomeEnum = null; 
      else 
      { 
       try 
       { 
        SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, false); 
       } 
       catch (Exception) 
       { 
        SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, true); 
       } 
      } 
     } 
    } 
} 

(Một yếu tố đó cùng một lúc có cả xsi:nil="true" và nội dung sẽ là một vi phạm XML standard; hy vọng bạn không có đó)

Sau đó sử dụng nó như:.

public class TestClass 
{ 
    [XmlElement("testTag.01")] 
    public testTag01 TestTag { get; set; } 

    public static void Test() 
    { 
     Test(new TestClass { TestTag = new testTag01 { NV = "123123" } }); 
     Test(new TestClass { TestTag = new testTag01 { NV = "123123", SomeEnum = SomeEnum.SomeValue } }); 
    } 

    private static void Test(TestClass test) 
    { 
     var xml = test.GetXml(); 

     var test2 = xml.LoadFromXML<TestClass>(); 

     Console.WriteLine(test2.GetXml()); 
     Debug.WriteLine(test2.GetXml()); 

     if (test2.TestTag.NV != test.TestTag.NV) 
     { 
      throw new InvalidOperationException("test2.TestTag.NV != test.TestTag.NV"); 
     } 
    } 
} 

Kết quả XML trông giống như:

<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <testTag.01 NV="123123" xsi:nil="true" /> 
</TestClass> 

Hoặc

<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <testTag.01 NV="123123">SomeValue</testTag.01> 
</TestClass> 

Prototype fiddle sử dụng các phương pháp khuyến nông:

public static class XmlSerializationHelper 
{ 
    public static T LoadFromXML<T>(this string xmlString, XmlSerializer serializer = null) 
    { 
     T returnValue = default(T); 

     using (StringReader reader = new StringReader(xmlString)) 
     { 
      object result = (serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader); 
      if (result is T) 
      { 
       returnValue = (T)result; 
      } 
     } 
     return returnValue; 
    } 

    public static string GetXml<T>(this T obj, XmlSerializerNamespaces ns = null, XmlWriterSettings settings = null, XmlSerializer serializer = null) 
    { 
     using (var textWriter = new StringWriter()) 
     { 
      settings = settings ?? new XmlWriterSettings() { Indent = true, IndentChars = " " }; // For cosmetic purposes. 
      using (var xmlWriter = XmlWriter.Create(textWriter, settings)) 
       (serializer ?? new XmlSerializer(typeof(T))).Serialize(xmlWriter, obj, ns); 
      return textWriter.ToString(); 
     } 
    } 
} 
0

Đúng như dự đoán không có giải pháp cho trường hợp đó ra khỏi hộp, vì vậy tôi improvise một chút và đạt được mục tiêu của tôi trong một logic bài chế biến.

Tôi đang phân tích cú pháp XML được tạo và nếu tôi đang tìm nút có thuộc tính xsi: nil, nhưng không có thuộc tính NV - tôi thêm thuộc tính NV với giá trị mặc định. Tương tự cho các nút có thuộc tính NV, nhưng không có xsi: nil.

Đây là mã:

 XmlDocument doc = new XmlDocument();// instantiate XmlDocument and load XML from file 
     doc.Load("somepath.xml"); 

     //Get the nodes with NV attribute(using XPath) and add xsi:nill to that nodes 
     XmlNodeList nodes = doc.SelectNodes("//*[@NV]"); 

     foreach (XmlNode node in nodes) 
     { 
      XmlAttribute nilAttr = doc.CreateAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance"); 
      nilAttr.Value = "true"; 
      node.Attributes.Append(nilAttr); 
     } 

     //Get the nodes with xsi:nill attribute(using XPath) and add NV with default value to that nodes 
     XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable); 
     nsManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); 
     XmlNodeList nilNodes = doc.SelectNodes("//*[@xsi:nil]", nsManager); 

     foreach (XmlNode node in nilNodes) 
     { 
      XmlAttribute nvAttr = doc.CreateAttribute("NV"); 
      nvAttr.Value = "7701003"; 
      node.Attributes.Append(nvAttr); 
     } 

     doc.Save("somepath.xml"); 

Câu trả lời trên làm hoàn toàn cảm giác, nhưng kể từ khi các lớp này được tự động tạo ra tôi sẽ làm theo cách của tôi với bài chế biến, gây ra nếu nhà cung cấp thay đổi lược đồ XSD, giải pháp của tôi không cần thêm bất kỳ công việc nào. Dù sao cũng cảm ơn bạn.

+1

Thực ra, tùy thuộc vào các phiên bản framework, bạn nên có thể phát ra lớp được tạo ra như một phần, sau đó bạn có thể bao gồm thuộc tính "luôn luôn nil" từ trên vào một tệp lớp thứ hai. –

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