如何展平这个XML

时间:2012-01-10 01:01:34

标签: c# xml linq

我收到如下的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

对于我来说,获取该List以及构建可以传递给DB的单独对象的最佳方法是什么。现在我得到明确的项目列表(这里是A&amp; B),然后将其传递给Lambda表达式,这样我就可以说给出Item = A和Position = X(0,1,2)的值。

只是想知道什么是最好的方法来“压扁”这个结构不良的XML。

5 个答案:

答案 0 :(得分: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 :(得分:1)

item属性上阅读xml和分组。

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

答案 2 :(得分: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 ;
        }

    }

}

答案 3 :(得分:0)

你在做什么可能是最好的方法。使用XSLT转换可以尝试一些魔法,但是当面对像你一直困扰的病态格式时,它们往往会变得脆弱。

答案 4 :(得分:0)

如果你无法控制xml的格式,我能想到的最好的事情就是使用结构并在lambda中实例化/填充一个实例,将对象输出到列表中。你走在正确的轨道上。