断言从XML解析的元素

本文关键字:元素 XML 断言 | 更新日期: 2023-09-27 18:19:09

我有一个使用XElement在c#中解析XML文档的类。

解析XML,例如:

IEnumerable<Element> elements =
    from topLevelElement in XElement.Parse(xml).Elements("topLevel")
    select new Element()
    {
        LongElement = Int64.Parse(topLevelElement.Element("long").Value),
        StringElement = topLevelElement.Element("string").Value,
        DateTimeElement = DateTime.Parse(topLevelElement.Element("datetime").Value)
    };

断言元素被正确解析的最好方法是什么?我想检查LongElement, StringElementDateTimeElement在解析后是否不为空,但如果有更好的方法可以做到这一点,我对此持开放态度。

断言从XML解析的元素

如果您不确定元素可能返回的值,您应该真正使用TryParse,例如

int i = 0;
string s = "3";
if (Int32.TryParse(s, out i))
{
    // Valid integer, now stored in i.
}
else
{
    // Invalid integer.
}
你的数据类型DateTime和Int32都有TryParse作为一个可用的方法。对于字符串,您可以执行简单的== nullString.IsNullOrEmpty

我会使用Linq内部的函数。如果你希望你的应用程序不那么严格,这些允许你抛出一个异常或设置所需的默认值;)

无论如何,你得到了更多的控制:

var elements = from topLevelElement in XElement.Parse(xml).Elements("topLevel")
               select new Element()
               {
                   LongElement = ConvertToInt(topLevelElement.Element("long").Value),
                   StringElement = topLevelElement.Element("string").Value,
                   DateTimeElement = DateTime.Parse(topLevelElement.Element("datetime").Value)
               };

ConvertToInt内可以做任何你想做的,比如:

    public int ConvertToInt(object value)
    {
       if(value is int)
         // return converted value
       else
         // return default, throw exception, etc
    }

我会将解析状态作为KeyValuePair存储在元素中:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var states = new string[] { "null", "empty", "noparse", "value" };
            var xml = "<root>";
            xml += "<topLevel><long>-13451245234</long><string>hello world</string><datetime>1/1/2012 8:00AM</datetime></topLevel>";
            xml += "<topLevel><long>4563264643</long><string>lipsum</string><datetime></datetime></topLevel>";
            xml += "<topLevel><string>hello world</string><datetime>1/1/2012 8:00AM</datetime></topLevel>";
            xml += "</root>";
        IEnumerable<Element> elements =
            from topLevelElement in XElement.Parse(xml).Elements("topLevel")
            select new Element
                       {
                           LongElement = ParseValue(topLevelElement, "long"),
                           DateTimeElement = ParseValue(topLevelElement, "datetime"),
                           StringElement = ParseValue(topLevelElement, "string"),
                       };
        var idx = 0;
        elements.All(e =>
        {
            Console.WriteLine("---- ELEMENT #{0} -----",idx++);
            Console.WriteLine("[long]     State: {0}'tValue:{1}'tType:{2}", states[e.LongElement.Key], e.LongElement.Value, (e.LongElement.Value).GetType());
            Console.WriteLine("[datetime] State: {0}'tValue:{1}'tType:{2}", states[e.DateTimeElement.Key], e.DateTimeElement.Value, (e.DateTimeElement.Value).GetType());
            Console.WriteLine("[string]   State: {0}'tValue:{1}'tType:{2}", states[e.StringElement.Key], e.StringElement.Value, (e.StringElement.Value).GetType());

            return true;
        });
    }
    private static dynamic ParseValue(XElement parent, String propname)
    {
        var prop = parent.Element(propname);
        dynamic val = null;
        byte state = 255;
        if (prop == null) state = 0;
        else if (string.IsNullOrEmpty(prop.Value)) state = 1;
        if (state < 255) return GetKVP(propname, state, GetDefaultValue(propname));

        switch (propname)
        {
            case "string":
                state = 3;
                val =  prop.Value;
                break;
            case "long":
                Int64 longvalue;
                if (Int64.TryParse(prop.Value, out longvalue)) { state = 3; val = longvalue; }
                else state = 2;
                break;
            case "datetime":
                DateTime datetimevalue;
                if (DateTime.TryParse(prop.Value, out datetimevalue)) { state = 3; val = datetimevalue; }
                else state = 2;
                break;
            default:
                val = GetDefaultValue(propname);
                break;
        }

        return GetKVP(propname,state,val);
    }
    private static dynamic GetKVP(string propname, byte state, object val)
    {
        if (propname == "long") return new KeyValuePair<byte, Int64>(state, (Int64)val);
        if (propname == "datetime") return new KeyValuePair<byte, DateTime>(state, (DateTime)val);
        if (propname == "string") return new KeyValuePair<byte, String>(state, (String)val);
        return null;
    }
    private static dynamic GetDefaultValue(string propname)
    {
        if (propname == "long") return long.MinValue;
        if (propname == "datetime") return DateTime.MinValue;
        if (propname == "string") return null;
        return null;
    }
    #region Nested type: Element
    public struct Element
    {
        // States stored as byte, 0 = null, 1= empty, 2 = has a value
        public KeyValuePair<byte,Int64> LongElement { get; set; }
        public KeyValuePair<byte,String> StringElement { get; set; }
        public KeyValuePair<byte,DateTime> DateTimeElement { get; set; }
    }
    #endregion
}
}
相关文章: