繁体   English   中英

解析XML属性的最佳方法

[英]Best way to parse XML Attributes

我有以下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);
}

如果我尝试获取不存在的certian属性的值,则代码将引发nullreferenceexception(IE:tNode.Attribute.GetNamedItem(“ repeat”)。value在所有没有重复属性的节点上都失败)。 我可以通过什么方法来验证某个属性是否存在?

上面的代码也不是干净的。 整理以上代码的最佳方法是什么?

编辑:我知道一种方法,您可以在获取值之前分别检查属性是否为null,但这会使代码看起来很脏,因为我需要编写大量的if(或嵌套的if)

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

从长远来看,如果我不得不编写更多的属性,这将成为问题。 我想更多地了解一种有组织的方法(也许可以枚举XML属性?我不知道。)

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

更新

现在您知道不会获得空引用,

最好的解决方案是编写一个类,使用XmlSerializer将xml反序列化到该类中。

有关自定义序列化的本文将帮助您入门。

要使用XML序列化,您必须首先使用指示所需XML映射的属性标记数据对象。 这些属性在System.Xml.Serialization命名空间中找到,包括以下内容:

XmlRoot指定XML文件的根元素的名称。 默认情况下,XmlSerializer将使用该类的名称。 该属性可以应用于类声明。

  • XmlElement指示用于属性或公共变量的元素名称。 默认情况下,XmlSerializer将使用属性或公共变量的名称。
  • XmlAttribute指示应将属性或公共变量序列化为属性而不是元素,并指定属性名称。
  • XmlEnum配置序列化枚举值时应使用的文本。 如果您不使用XmlEnum,则将使用枚举常量的名称。
  • XmlIgnore指示不应序列化属性或公共变量。

同意@nunespascal,这是我已经为您准备的代码..他的回答比我更快..大声笑:

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

那应该使您有个良好的开端。 祝好运。

好吧,这是一个完全未经测试的混搭功能,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");

.. 或者其他的东西。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM