如何使用LINQ将xml解析为带有XDocument的Object

时间:2016-09-28 15:35:00

标签: c# xml linq

我有一个xml文件如下:

<Message xsi:schemaLocation ="..">
    <Header>..</Header>
    <Body>
        <History 
            xmlns="..">
            <Number></Number>
            <Name></Name>
            <Item>
                <CreateDate>..</CreateDate>
                <Type>..</Type>
                <Description></Description>
            </Item>
            <Item>
                <CreateDate>..</CreateDate>
                <Type>..</Type>
                <Description>1..</Description>
                <Description>2..</Description>
            </Item>
        </History>
    </Body>
</Message>

我想创建并将其作为History对象进行对象。

public class History
{
    public string Name { get; set; }
    public string Number { get; set; }
    public List<Item> Items { get; set; }

}



    var xElement = XDocument.Parse(xmlString);

    XElement body = (XElement)xElement.Root.LastNode;
    XElement historyElement = (XElement)body.LastNode;

    var history = new History
    {
        Name = (string)historyElement.Element("Name"),
        Number = (string)historyElement.Element("Number"),
        Items = (
               from e in historyElement.Elements("Item")
               select new Item
               {
                   CraeteDate = DateTime.Parse(e.Element("CreateDate").Value),
                   Type = (string)e.Element("Type").Value,
                   Description = string.Join(",",
                       from p in e.Elements("Description") select (string)p.Element("Description"))
               }).ToList()

    };

为什么这不起作用?

值始终为null。

似乎&#34; historyElement.Element(&#34; Name&#34;)&#34;即使元素有一个元素和值,它也总是为空。

知道我错过了什么吗?

由于

2 个答案:

答案 0 :(得分:2)

这是由于名称空间,请尝试这样做:

XNamespace ns =  "http://schemas.microsoft.com/search/local/ws/rest/v1";// the namespace you have in the history element
var xElement = XDocument.Parse(xmlString);

var history= xElement.Descendants(ns+"History")
                     .Select(historyElement=>new History{ Name = (string)historyElement.Element(ns+"Name"),
                                                          Number = (string)historyElement.Element(ns+"Number"),
                                                          Items = (from e in historyElement.Elements(ns+"Item")
                                                                   select new Item
                                                                          {
                                                                            CraeteDate= DateTime.Parse(e.Element(ns+"CreateDate").Value),
                                                                            Type = (string) e.Element(ns+"Type").Value,
                                                                            Description= string.Join(",",
                                                                             from p in e.Elements(ns+"Description") select (string)p)
                                                                           }).ToList()
                                                          }).FirstOrDefault();

如果您想了解有关此主题的更多信息,请查看此link

答案 1 :(得分:1)

这里有一些小问题,xml在这里格格不入。所以不得不花一些时间来测试并使其工作。

你在前面有一个xsi,我认为它应该是xsd中提到的某个地方。

如果您的xml节点在此处解析xml树时,如果您的xml节点附加了命名空间,则必须附加命名空间:

我的示例解决方案如下所示:

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

namespace ConsoleApplication1
{
    public class History
    {
        public string Name { get; set; }
        public string Number { get; set; }
        public List<Item> Items { get; set; }

    }

    public class Item
    {
        public DateTime? CreateDate { get; set; }
        public string Type { get; set; }
        public string Description { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string xmlString =
                @"<Message>
                    <Header>..</Header>
                    <Body>
                        <History 
                            xmlns=""http://schemas.somewhere.com/types/history"">
                            <Number>12</Number>
                            <Name>History Name</Name>
                            <Item>
                                <CreateDate></CreateDate>
                                <Type>Item 1 Type</Type>
                                <Description>Item 1 Description</Description>
                            </Item>
                            <Item>
                                <CreateDate></CreateDate>
                                <Type>Item 2 Type</Type>
                                <Description>Item 2 Description 1</Description>
                                <Description>Item 2 Description 2</Description>
                            </Item>
                        </History>
                    </Body>
                </Message>";


            XNamespace ns = "http://schemas.somewhere.com/types/history";
            var xElement = XDocument.Parse(xmlString);

            var historyObject = xElement.Descendants(ns +"History")
                .Select(historyElement => new History
                {
                    Name = historyElement.Element(ns + "Name")?.Value,
                    Number = historyElement.Element(ns + "Number")?.Value,
                    Items = historyElement.Elements(ns + "Item").Select(x => new Item()
                    {
                        CreateDate = DateTime.Parse(x.Element(ns + "CreateDate")?.Value),
                        Type = x.Element(ns + "Type")?.Value,
                        Description = string.Join(",", x.Elements(ns + "Description").Select(elem=>elem.Value))
                    }).ToList()
                }).FirstOrDefault();
        }
    }
}

如果您不想关注查找命名空间,可能需要尝试以下操作:

    var document = XDocument.Parse(xmlString);
    var historyObject2 = document.Root.Descendants()
        .Where(x=>x.Name.LocalName == "History")
        .Select(historyElement => new History
        {
            Name = historyElement.Element(historyElement.Name.Namespace + "Name")?.Value,
            Number = historyElement.Element(historyElement.Name.Namespace+ "Number")?.Value,
            Items = historyElement.Elements(historyElement.Name.Namespace + "Item").Select(x => new Item()
            {
                //CreateDate = DateTime.Parse(x.Element("CreateDate")?.Value),
                Type = x.Element(historyElement.Name.Namespace + "Type")?.Value,
                Description = string.Join(",", x.Elements(historyElement.Name.Namespace + "Description").Select(elem => elem.Value))
            }).ToList()
        }).FirstOrDefault();