2012-07-20 87 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"); 

..什么的。