使用正确的 xsd 解析 xml:类型

parse xml with correct xsd: type

我有 XML 包含这样的元素

<Value xsi:type="xsd:short">0</Value>
<Value xsi:type="xsd:string">foo</Value>
<Value xsi:type="xsd:boolean">false</Value>
<!-- ... many other types -->

我如何自动 parse/deserialize 以正确的 .NET 类型 that corresponds 和 xsd 获取 Value 元素的内容:类型(例如 System.Int16System.StringSystem.Boolean)?

这是我尝试过的方法,但它有点脆弱,所有这些 .NET XML API 中必须有内置方法。

foreach (var value in XDocument.Load(new StreamReader(@"c:\bar.xml")).Descendants("Value"))
{
    var actualValue = GetValue(value);
}

...

// TODO: Get rid of this hand written method, .NET should do this for me
private static object GetValue(XElement value)
{
    XNamespace ns = "http://www.w3.org/2001/XMLSchema-instance";
    var type = value.Attributes(ns + "type").Single().Value;
    switch (type)
    {
        case "xsd:short":
            return (short)value;  
        case "xsd:boolean":
            return (bool)value;
        case "xsd:string":
            return (string)value;    
        ...                  
    }        

    throw new UnknownTypeException();
}

试试这个

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

namespace ConsoleApplication11
{
    class Program
    {
        static void Main(string[] args)
        {
            List<object> values = new List<object>();
            string xml =
                "<Root xmlns:xsi = \"abc\">" +
                    "<Value xsi:type=\"xsd:short\">0</Value>" +
                    "<Value xsi:type=\"xsd:string\">foo</Value>" +
                    "<Value xsi:type=\"xsd:boolean\">false</Value>" +
                "</Root>";
            XElement root = XElement.Parse(xml);
            XNamespace ns = root.GetDefaultNamespace();
            foreach(XElement value in root.Descendants("Value"))
            {
                string _type = (string)value.Attributes().Where(x => x.Name.LocalName == "type").FirstOrDefault();
                switch (_type)
                {
                    case "xsd:short"  :
                        values.Add((short)value);
                        break;
                    case "xsd:string":
                        values.Add((string)value);
                        break;
                    case "xsd:boolean":
                        values.Add((Boolean)value);
                        break;
                }

            }

        }
    }
}

假设您只能期望内置类型,您可以创建一个 XML 序列化程序来反序列化这些值。幸运的是,您的属性名称与预期名称匹配,因此您无需执行任何转换。

XNamespace xsd = "http://www.w3.org/2001/XMLSchema";
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
var doc = new XDocument(
    new XElement("root",
        new XAttribute(XNamespace.Xmlns + "xsd", xsd),
        new XAttribute(XNamespace.Xmlns + "xsi", xsi),
        new XElement("Value", new XAttribute(xsi + "type", "xsd:short"), (short)0),
        new XElement("Value", new XAttribute(xsi + "type", "xsd:string"), "foo"),
        new XElement("Value", new XAttribute(xsi + "type", "xsd:boolean"), false)
    )
);

var serializer = new XmlSerializer(typeof(object), new XmlRootAttribute("Value"));
var values = doc.Descendants("Value")
    .Select(v => serializer.Deserialize(v.CreateReader()));