断言从XML解析的元素

时间:2011-12-30 14:21:20

标签: c# .net xml linq linq-to-xml

我有一个使用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)
    };

断言元素被正确解析的最佳方法是什么?我想在解析后检查LongElementStringElementDateTimeElement是否为空,但如果有更好的方法可以解决这个问题,我愿意接受它。

3 个答案:

答案 0 :(得分:3)

如果您不确定元素可能返回的值,您应该使用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

答案 1 :(得分:0)

我会使用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
    }

这也是一种更可重复使用的布局。

答案 2 :(得分:0)

我会将解析状态存储在元素中作为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
}
}