2012-07-20 91 views
0

我已經被解析,需要下面的XML文檔:最佳方式屬性

... 
<tx size_total="143"> 
    <type size="1" start_key="02">STX</type> 
    <type size="3">Type</type> 
    <type size="3" decimal="true">Serial</type> 
    <type size="3" key="23 64 31">Function_Code</type> 
    <type size="2" decimal="true">LIU</type> 
    <type size="1">Status</type> 
    <type size="2" repeat="64" binary ="true" binary_discard="2">Value</type> 
    <type size="1">ETX</type> 
    <type size="1">LRC</type> 
... 

我寫了下面的代碼解析:

XmlNodeList typeNodeList = txNode.SelectNodes(TYPE_NODE); 
CommRuleContainer rc = new CommRuleContainer(funcNode.Attributes.GetNamedItem("name").Value, 
         txNode.Attributes.GetNamedItem("size_total").Value, funcNode.Attributes.GetNamedItem("id").Value); 
foreach (XmlNode tNode in typeNodeList) 
{ 
    int size = Convert.ToInt32(tNode.Attributes.GetNamedItem("size").Value); 
    int repeat = Convert.ToInt32(tNode.Attributes.GetNamedItem("repeat").Value); 
    int binary_discard = Convert.ToInt32(tNode.Attributes.GetNamedItem("binary_discard").Value); 
    string start_key = tNode.Attributes.GetNamedItem("start_key").Value; 
    string key = tNode.Attributes.GetNamedItem("key").Value; 
    bool convert_decimal = false, convert_binary = false; 
    if (tNode.Attributes.GetNamedItem("decimal").Value == "true") 
           convert_decimal = true; 
    if (tNode.Attributes.GetNamedItem("binary").Value == "true") 
           convert_binary = true; 
    rc.AddTypeDefinition(tNode.Value, size, repeat, binary_discard, convert_decimal, convert_binary); 
} 

的代碼拋出一個NullReferenceException如果我嘗試獲取不存在的certian屬性的值(IE:tNode.Attribute.GetNamedItem(「repeat」)。值在所有沒有repeat屬性的節點上失敗)。什麼是我可以驗證某個屬性是否存在的方法?

此外上面的代碼根本不乾淨。組織上述代碼的最佳方式是什麼?

編輯:我知道的方法,您可以單獨檢查屬性是否爲null或不從它們的值之前,但這使得代碼看起來非常骯髒,因爲我需要寫很多ifs(或嵌套的ifs)

if (tNode.Attributes.GetNamedItem("decimal") != null) 
    if (tNode.Attributes.GetNamedItem("decimal").Value == "true") 
     convert_decimal = true; 

從長遠來看,如果我必須編寫更多的屬性,這會變得有問題。我想知道更多的這種有組織的方法(可能XML屬性可以枚舉?我不知道。)

回答

2

與@nunespascal這裏同意是我對你已經準備..他比我回答越快代碼.. LOL:

static void Main(string[] args) 
     { 
      var serialized = @" 
<tx size_total=""143""> 
    <type size=""1"" start_key=""02"">STX</type> 
    <type size=""3"">Type</type> 
    <type size=""3"" decimal=""true"">Serial</type> 
    <type size=""3"" key=""23 64 31"">Function_Code</type> 
    <type size=""2"" decimal=""true"">LIU</type> 
    <type size=""1"">Status</type> 
    <type size=""2"" repeat=""64"" binary =""true"" binary_discard=""2"">Value</type> 
    <type size=""1"">ETX</type> 
    <type size=""1"">LRC</type></tx>"; 
      var deserialized = serialized.XmlDeserialize<Tx>(); 
     } 
    } 

    [XmlRoot("tx")] 
    public class Tx 
    { 
     [XmlAttribute("size_total")] 
     public int TotalSize { get; set; } 

     [XmlElement("type")] 
     public List<TxType> Types { get; set; } 

     public Tx() 
     { 
      Types = new List<TxType>(); 
     } 
    } 

    public class TxType 
    { 
     [XmlAttribute("size")] 
     public string Size { get; set; } 

     [XmlAttribute("decimal")] 
     public bool IsDecimal { get; set; } 

     [XmlAttribute("binary")] 
     public bool IsBinary { get; set; } 

     [XmlAttribute("start_key")] 
     public string StartKey { get; set; } 

     [XmlAttribute("key")] 
     public string Key { get; set; } 

     [XmlAttribute("repeat")] 
     public int Repeat { get; set; } 

     [XmlAttribute("binary_discard")] 
     public int BinaryDiscard { get; set; } 

     [XmlText] 
     public string Value { get; set; } 
    } 

這裏是我的反序列化的輔助類:

public static class StringExtensions 
    { 
     /// <summary> 
     /// Deserializes the XML data contained by the specified System.String 
     /// </summary> 
     /// <typeparam name="T">The type of System.Object to be deserialized</typeparam> 
     /// <param name="s">The System.String containing XML data</param> 
     /// <returns>The System.Object being deserialized.</returns> 
     public static T XmlDeserialize<T>(this string s) 
     { 
      var locker = new object(); 
      var stringReader = new StringReader(s); 
      var reader = new XmlTextReader(stringReader); 
      try 
      { 
       var xmlSerializer = new XmlSerializer(typeof(T)); 
       lock (locker) 
       { 
        var item = (T)xmlSerializer.Deserialize(reader); 
        reader.Close(); 
        return item; 
       } 
      } 
      catch 
      { 
       return default(T); 
      } 
      finally 
      { 
       reader.Close(); 
      } 
     } 
    } 

這應該讓你開始一個好開始。祝你好運。

+0

豎起大拇指爲我的要求和寫一個示例代碼。如果有多個使用相同屬性的根,是否有合適的說法[XmlRoot(「tx」)],[XmlRoot(「rx」)]表示可以在執行任何一個根時引用同一個類反序列化? – l46kok 2012-07-20 05:28:18

2
if(null != tNode.Attributes.GetNamedItem("repeat")) 
    repeat = Convert.ToInt32(tNode.Attributes.GetNamedItem("repeat").Value); 

更新

現在你知道不在於拿null reference,

最好的解決方案是編寫一個類,使用XmlSerializer來反序列化你的xml。

這篇關於custom serialization的文章將幫助您入門。

要使用XML序列化,必須首先使用指示所需XML映射的屬性標記數據對象 。這些 屬性位於System.Xml.Serialization命名空間中,並且 包括以下內容:

XmlRoot指定XML文件的根元素的名稱。默認情況下,XmlSerializer將使用該類的名稱。該屬性 可應用於類聲明。

  • XmlElementIndicates元素的名稱使用的財產或公共變量。默認情況下,XmlSerializer將使用屬性或公共變量的名稱。
  • XmlAttribute指示應該將屬性或公共變量序列化爲屬性而不是元素並指定屬性名稱。
  • XmlEnumConfigures在序列化枚舉值時應使用的文本。如果您不使用XmlEnum,則將使用枚舉常量的名稱。
  • XmlIgnore指示不應序列化屬性或公共變量。
+0

我想過這種方法,但我想知道是否有其他方法,因爲如果我有很多屬性需要照顧,這會使我的代碼看起來非常糟糕。 – l46kok 2012-07-20 04:36:48

+0

確實有更好的方法,但我覺得如果你不能自己解決空引用;解釋其他方法可能有點困難。 – nunespascal 2012-07-20 04:38:50

+0

我故意沒有提到這裏發佈的解決方案,因爲我認爲單獨檢查每個可能屬性上的空項目並不是一個好方法。我繼續編輯OP。 – l46kok 2012-07-20 04:42:10

1

那麼,這裏是一個完全未經測試的mashup函數YMMV。

static class XmlNodeExtensions { 
    public static T GetAttrValue(this XmlNode node, string attrName) { 
     return GetAttrValue(node, attrName, default(T)); 
    } 
    public static T GetAttrValue(this XmlNode node, string attrName, T defaultValue) { 
     var attr = node.Attributes.GetNamedItem(attrName); 
     if (attr != null) { 
      var value = attr.Value; 
      var tT = typeof(T);  // target Type 
      if (tT.IsAssignableFrom(typeof(string))) 
      { 
       return (T)value; 
      } else 
      { 
       var converter = TypeDescriptor.GetConverter(tT); 
       if (converter.CanConvertFrom(typeof(string))) 
       { 
        return (T)converter.ConvertFrom(value); 
       } else 
       { 
        throw new InvalidOperationException("No conversion possible"); 
       } 
      } 
     } else { 
      return defaultValue; 
     } 
    } 
} 

..然後..

var id = node.GetAttrValue<int>("size"); 
var name = node.GetAttrValue("name", "no name!"); 
var titleOrNull = node.GetAttrValue<string>("title"); 

..什麼的。