2012-01-10 77 views
0

我收到的XML消息的形式大致如下(相信我,這不是我多麼希望它):如何扁平化這個XML

<items> 
<item item="A" position="0"> 
    <itemvalue>10</itemvalue> 
</item> 
    <item item="A" position="1"> 
    <itemvalue>20</itemvalue> 
</item> 
    <item item="A" position="2"> 
    <itemvalue>30</itemvalue> 
</item> 
    <item item="B" position="0"> 
    <itemvalue>10</itemvalue> 
    </item> 
    <item item="B" position="1"> 
    <itemvalue>20</itemvalue> 
    </item> 
    <item item="B" position="2"> 
    <itemvalue>30</itemvalue> 
</item> 
</items> 

我撕碎使用LINQ的XML。所以我得到的是項目列表|位置|值。我真的希望數據是匹配我的表結構。

Item | Column1 | Column2 | Column3 
A   10  20  30 

什麼是最好的方式讓我採取該名單和建立一個單獨的對象我可以傳遞給數據庫。現在,我得到了不同的項目清單(在這裏是A & B),然後將它傳遞給Lambda表達式,以便我可以告訴給我Item = A和Position = X(0,1,2)的值。

只是想知道什麼是最好的方法來「扁平」這個結構不好的XML。

+0

你可以只創建一個字典,用結構像詞典<字符串,字典>然後通過將文檔掃描,填充此詞典..一旦數據在那裏,它是'平'(ish)格式,這很容易格式化。或者,也可以創建一個新的xml文檔,並用所需的格式填充它。 – 2012-01-10 01:14:06

+0

[相關MSDN主題](http://social.msdn.microsoft.com/forums/en-US/xmlandnetfx/thread/898cf984-439b-4dbe-89eb-07d2690b47b7) – 2012-01-10 01:16:30

+0

難道你不是指「unflatten」嗎? – harpo 2012-01-10 01:18:52

回答

1

閱讀xml和item屬性組。

var result = from ele in doc.Descendants("item") 
      group ele by ele.Attribute("item").Value into grp 
      select grp; 
foreach (var t in result) 
{ 
    XElement[] ar = t.ToArray(); 
    Console.WriteLine(t.Key + " "+ ar[0].Value + " " + ar[1].Value + " " + ar[2].Value ); 
} 
0

你在做什麼可能是最好的方法。您可以嘗試使用XSLT轉換來實現一些魔法,但在遇到像您所遇到的病態格式時,它們往往會變得脆弱。

0

如果你無法控制xml的格式,我能想到的最好的方法就是在你的lambda中使用結構並實例化/填充一個實例,將對象輸出到列表中。你在正確的軌道上。

2

代碼:

static void Main(string[] args) 
{ 
    var xml = XDocument.Parse("<items><item item=\"A\" position=\"0\"><itemvalue>10</itemvalue></item><item item=\"A\" position=\"1\"><itemvalue>20</itemvalue>" 
     + "</item><item item=\"A\" position=\"2\"><itemvalue>30</itemvalue></item><item item=\"B\" position=\"0\"><itemvalue>10</itemvalue>" 
     + "</item><item item=\"B\" position=\"1\"><itemvalue>20</itemvalue></item><item item=\"B\" position=\"2\"><itemvalue>30</itemvalue>" 
     + "</item></items>").Root; 

    var keys = xml.Elements() 
        .GroupBy(x => x.Attribute("item").Value) 
        .Select(x => x.Key); 

    var flattened = new XDocument(); 

    flattened.Add(new XElement("flattened")); 

    foreach (var item in keys) 
    { 
     var elements = xml.Elements().Where(x => x.Attribute("item").Value == item); 

     flattened.Root.Add(new XElement("Item", new XAttribute("Item", elements.First().Attribute("item").Value) 
      , new XAttribute("Column1", elements.First().Element("itemvalue").Value) 
      , new XAttribute("Column2", elements.ElementAt(1).Element("itemvalue").Value) 
      , new XAttribute("Column3", elements.Last().Element("itemvalue").Value))); 
    } 

    Console.WriteLine(flattened.ToString()); 

    Console.ReadLine(); 
} 

結果:

enter image description here

1

可以編寫XSLT重新安排的事情,我有一個深刻的厭惡使用XML作爲一種編程語言。緙!

雖然這樣的事情應該做的伎倆。有一點XML序列化和一個非常簡單的變換:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Xml; 
using System.Xml.Serialization; 

namespace ConsoleApplication22 
{ 

    [XmlRoot("items")] 
    public class ItemList 
    { 
     public static ItemList CreateInstance(string xml) 
     { 
      ItemList instance = null ; 

      using (TextReader tr = new StringReader(xml)) 
      { 
       XmlSerializer serializer = new XmlSerializer(typeof(ItemList)) ; 

       instance = (ItemList) serializer.Deserialize(tr) ; 

      } 

      return instance ; 

     } 

     public SimpleItem[] Simplify() 
     { 
      return Items.OrderBy(x => x.Name ) 
         .ThenBy( x => x.Position) 
         .GroupBy(x => x.Name , x => x , (name,group) => SimpleItem.CreateInstance(name,group)) 
         .ToArray() 
         ; 
     } 

     [XmlElement("item")] 
     public Item[] Items { get ; set ; } 

    } 

    public class Item 
    { 

     [XmlAttribute("item")] 
     public string Name { get ; set ; } 

     [XmlAttribute("position")] 
     public int Position { get ; set ; } 

     [XmlElement("itemvalue")] 
     public int Value { get ; set ; } 

    } 

    public class SimpleItem 
    { 

     public static SimpleItem CreateInstance(string name , IEnumerable<Item> items) 
     { 
      List<int> values = new List<int>() ; 
      int  i  = 0 ; 
      foreach(Item item in items.OrderBy(x => x.Position)) 
      { 
       if (item.Position != i++) throw new InvalidOperationException("bad data") ; 
       values.Add(item.Value) ; 
      } 
      SimpleItem instance = new SimpleItem(name , values.ToArray()) ; 

      return instance ; 
     } 

     private SimpleItem(string name , int[] values) 
     { 
      this.Name = name ; 
      this.Columns = values ; 
      return ; 
     } 

     public string Name { get ; private set ; } 
     public int[] Columns { get ; private set ; } 

    } 

    class Program 
    { 

     static void Main(string[] args) 
     { 
      string xml = @" 
<items> 
<item item=""A"" position=""0""> 
    <itemvalue>10</itemvalue> 
</item> 
    <item item=""A"" position=""1""> 
    <itemvalue>20</itemvalue> 
</item> 
    <item item=""A"" position=""2""> 
    <itemvalue>30</itemvalue> 
</item> 
    <item item=""B"" position=""0""> 
    <itemvalue>10</itemvalue> 
    </item> 
    <item item=""B"" position=""1""> 
    <itemvalue>20</itemvalue> 
    </item> 
    <item item=""B"" position=""2""> 
    <itemvalue>30</itemvalue> 
</item> 
</items> 
" ; 

      ItemList  instance = ItemList.CreateInstance(xml) ; 
      SimpleItem[] items = instance.Simplify() ; 

      return ; 
     } 

    } 

}