2016-02-25 47 views
0

解析这个不寻常的xml文档的最佳方法是什么?解析XML文档(使用不寻常的格式)C#

部分XML的:

<?xml version="1.0" encoding="UTF-8"?> 
<dataset xmlns="http://developer.cognos.com/schemas/xmldata/1/" 
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"> 
    <metadata> 
     <item name="AsOfDate" type="xs:string" length="12"/> 
     <item name="RateOfReturn" type="xs:double"/> 
     <item name="FamAcctIndex" type="xs:string" length="3"/> 
     <item name="RowID" type="xs:string" length="1"/> 
     <item name="BrM" type="xs:string" length="1"/> 
     <item name="ProductLineCode" type="xs:int"/> 
    </metadata> 
    <data> 
     <row> 
      <value>Apr 26, 2002</value> 
      <value>0.210066429</value> 
      <value>JA1</value> 
      <value>F</value> 
      <value>B</value> 
      <value>1</value> 
     </row> 
     <row> 
      <value>Apr 27, 2002</value> 
      <value>0.1111111</value> 
      <value>BBB</value> 
      <value>G</value> 
      <value>B</value> 
      <value>2</value> 
     </row>  
    </data> 
</dataset> 

当我说的不寻常的XML文档,我的意思是我从未有过解析的数据/行的东西。这是我通常会看到:

<person gender="female"> 
    <firstname>Anna</firstname> 
    <lastname>Smith</lastname> 
</person> 

我打算用:

var xmlDoc = new XmlDocument(); 
xmlDoc.Load(stream); 
//parse here 

但想我会想知道之前做到这一点的最好办法入门,因为它是一个非常大的文件。

编辑:

这是最好的方法吗?

var xml = XElement.Load(@"C:\Users\nunya\Desktop\example.xml").Element(XName.Get("data", "http://developer.cognos.com/schemas/xmldata/1/")); 
var row = XName.Get("row", "http://developer.cognos.com/schemas/xmldata/1/"); 
var value = XName.Get("value", "http://developer.cognos.com/schemas/xmldata/1/"); 


if (xml != null) 
{ 
    foreach (var rowElement in xml.Elements(row)) 
    { 
     foreach (var valueElement in rowElement.Elements(value)) 
     { 
      //valueElement.Value is what i need 
     } 
    } 
} 

谢谢!

+0

您是否曾经使用过由集合中的多个元素组成的XML?如果是这样,这真的没有什么不同。 – BoltClock

+0

你应该使用'XElement'。 – SLaks

+0

这个XML可能是通过序列化一个DataTable或类似的东西而创建的。 –

回答

1

假设你有一个模式或者可以生成一个可靠的对象,你可以将对象序列化为一个C#类,但是这仍然会使其操作变得复杂。我会创建一个具有与标题值匹配的属性的类。您可以尝试在该类的父级上实现IXmlSerializable,但我认为使用XDocument来编写返回列表的内容会更直接。

基本问题是弄清楚如何将列索引与行值索引对齐。我做到了使用字典和一个列表:

public class Product 
{ 
    public string AsOfDate { get; set; } 
    public double RateOfReturn { get; set; } 
    public string FamAcctIndex { get; set; } 
    public string RowID { get; set; } 
    public string BrM { get; set; } 
    public int ProductLineCode { get; set; } 
} 


public static IEnumerable<Product> ParseDataset(XDocument xd) 
{ 
    XNamespace ns = "http://developer.cognos.com/schemas/xmldata/1/"; 

    // parse out the column names 
    Dictionary<string, int> headerPositions = xd.Root 
     .Element(ns + "metadata") 
     .Elements() 
     .Select((name, idx) => new { pos = idx, name = (string)name.Attribute("name") }) 
     .ToDictionary(x => x.name, x => x.pos); 

    foreach (XElement row in xd.Root.Descendants(ns + "row")) 
    { 
     List<string> vals = row.Elements().Select(x => x.Value).ToList(); 
     Product obj = new Product(); 
     foreach (PropertyInfo prop in typeof(Product).GetProperties()) 
     { 
      string valToSet = vals[headerPositions[prop.Name]]; 
      prop.SetValue(obj, Convert.ChangeType(valToSet, prop.PropertyType); 
     } 
     yield return obj; 
    } 
} 

如果性能是一个问题,你可能要避免使用反射,只是使用if /交换机上的属性名称。您可以调用函数,如

XDocument xd = XDocument.Load(...); 
List<Product> products = ParseDataset(xd).ToList();