2012-01-10 83 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 ; 
     } 

    } 

}