2016-02-25 46 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();