如何用LINQ解析xml到用XDocument的对象

本文关键字:XDocument 对象 到用 xml 何用 LINQ 解析 | 更新日期: 2023-09-27 18:09:22

我有一个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>

我想创建一个对象作为历史对象。

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。

似乎" historyelelement . element ("Name")"总是空的,即使有一个元素和值的元素。

你知道我错过了什么吗?

谢谢

如何用LINQ解析xml到用XDocument的对象

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

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

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

这里有几件小事,这里的xml格式有问题。所以必须花一些时间来测试并使其工作。

前面有一个xsi,我想应该在xsd中提到过。

解析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();