【问题标题】:parse xml with correct xsd: type使用正确的 xsd 解析 xml:类型
【发布时间】:2016-08-24 13:51:10
【问题描述】:

我的 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 -->

我如何自动解析/反序列化它,以便我使用 xsd: 类型(例如 System.Int16System.String、@987654326 @)?

这是我尝试过的,但它有点脆弱,所有这些 .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();
}

【问题讨论】:

    标签: c# xml linq-to-xml xmldocument xmlreader


    【解决方案1】:

    假设您只能期望内置类型,您可以创建一个 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()));
    

    【讨论】:

      【解决方案2】:

      试试这个

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

      【讨论】:

      • 这与我的解决方案有何不同?我的解决方案已经奏效。由于 switch 语句,我想完全 摆脱GetValue 方法。您刚刚内联了该方法。
      猜你喜欢
      • 1970-01-01
      • 2014-05-13
      • 2021-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-11
      相关资源
      最近更新 更多