简体   繁体   English

当多个元素具有相同名称时,如何使用c#和XDocument将XML解析为对象?

[英]How to parse XML using c# and XDocument into an object when multiple elements have the same name?

I'm using SharePoint 2013's REST API to get XML to parse, but I'm having trouble parsing a certain chunk of XML. 我正在使用SharePoint 2013的REST API来解析XML,但是在解析XML的特定块时遇到了麻烦。 Here's a truncated example of some XML I might get back that I have no problem parsing: 这是一些XML的截断的示例,我可能会回过头来解析没有问题:

<feed xml:base="http://server/DesktopApplications/_api/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
  <id>2dff4586-6b7d-4186-ae63-4d048f74a112</id>
  <title />
  <updated>2014-03-19T15:32:15Z</updated>
  <entry m:etag=""19"">
    <id>http://server/DesktopApplications/_api/Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')</id>
    <category term="SP.List" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <link rel="edit" href="Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')" />
    <title />
    <updated>2014-03-19T15:32:15Z</updated>
    <author>
      <name />
    </author>
    <content type="application/xml">
      <m:properties>
        <d:BaseTemplate m:type="Edm.Int32">101</d:BaseTemplate>
        <d:BaseType m:type="Edm.Int32">1</d:BaseType>
        <d:Id m:type="Edm.Guid">0ac46109-38d9-4070-96b7-f90085b56f1e</d:Id>
        <d:ListItemEntityTypeFullName>SP.Data.Shared_x0020_DocumentsItem</d:ListItemEntityTypeFullName>
        <d:Title>Documents</d:Title>
      </m:properties>
    </content>
  </entry>
  ...
</feed>

I can parse this just fine using XDocument with the following: 我可以使用XDocument将其解析为以下内容:

private static readonly XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
private static readonly XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";

...    

List<KLList> lists = doc.Descendants(m + "properties").Select(
    list => new KLList() 
    { 
        Id = list.Element(d + "Id").Value, 
        Title = list.Element(d + "Title").Value,
        ListItemEntityTypeFullName = list.Element(d + "ListItemEntityTypeFullName").Value,
        BaseType = (BaseType)Convert.ToInt32(list.Element(d + "BaseType").Value),
        ListTemplateType = (ListTemplateType)Convert.ToInt32(list.Element(d + "BaseTemplate").Value)
    }).ToList();

When I expand my query to get the server relative url of the list's root folder, I get XML like this that I have trouble with: 当我扩展查询以获取列表的根文件夹的服务器相对URL时,我得到了这样的XML,但我遇到了麻烦:

<feed xml:base="http://server/DesktopApplications/_api/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
  <id>a01c22dc-a87f-4253-91d1-0a6ef8efa6d0</id>
  <title />
  <updated>2014-03-19T15:27:11Z</updated>
  <entry m:etag=""19"">
    <id>http://server/DesktopApplications/_api/Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')</id>
    <category term="SP.List" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <link rel="edit" href="Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RootFolder" type="application/atom+xml;type=entry" title="RootFolder" href="Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')/RootFolder">
      <m:inline>
        <entry>
          <id>http://server/DesktopApplications/_api/Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')/RootFolder</id>
          <category term="SP.Folder" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
          <link rel="edit" href="Web/Lists(guid'0ac46109-38d9-4070-96b7-f90085b56f1e')/RootFolder" />
          <title />
          <updated>2014-03-19T15:27:11Z</updated>
          <author>
            <name />
          </author>
          <content type="application/xml">
            <m:properties>
              <d:ServerRelativeUrl>/DesktopApplications/Shared Documents</d:ServerRelativeUrl>
            </m:properties>
          </content>
        </entry>
      </m:inline>
    </link>
    <title />
    <updated>2014-03-19T15:27:11Z</updated>
    <author>
      <name />
    </author>
    <content type="application/xml">
      <m:properties>
        <d:BaseTemplate m:type="Edm.Int32">101</d:BaseTemplate>
        <d:BaseType m:type="Edm.Int32">1</d:BaseType>
        <d:Id m:type="Edm.Guid">0ac46109-38d9-4070-96b7-f90085b56f1e</d:Id>
        <d:ListItemEntityTypeFullName>SP.Data.Shared_x0020_DocumentsItem</d:ListItemEntityTypeFullName>
        <d:Title>Documents</d:Title>
      </m:properties>
    </content>
  </entry>
  ...
</feed>

I tried using basically the same code because I want the ServerRelativeUrl to be on the same object: 我尝试使用基本相同的代码,因为我希望ServerRelativeUrl位于同一对象上:

List<KLList> lists = doc.Descendants(m + "properties").Select(
    list => new KLList() 
    { 
        Id = list.Element(d + "Id").Value, 
        Title = list.Element(d + "Title").Value,
        ListItemEntityTypeFullName = list.Element(d + "ListItemEntityTypeFullName").Value,
        BaseType = (BaseType)Convert.ToInt32(list.Element(d + "BaseType").Value),
        ListTemplateType = (ListTemplateType)Convert.ToInt32(list.Element(d + "BaseTemplate").Value),
        RelativeUrl = list.Element(d + "ServerRelativeUrl").Value
    }).ToList();

But this no longer works. 但是,这不再起作用。 The first thing doc.Descendants(m + "properties") returns is doc.Descendants(m + "properties")返回的第一件事是

<m:properties>
    <d:ServerRelativeUrl>/DesktopApplications/Shared Documents</d:ServerRelativeUrl>
</m:properties>

so trying to set the other properties at the same time throws an object reference exception, because the other elements aren't here. 因此尝试同时设置其他属性会引发对象引用异常,因为其他元素不在此处。

How can I parse this XML so that all of the values I want go into one object? 如何解析该XML,以便将所有想要的值放入一个对象中? I'd rather not have to make a separate call to get the root folder url for each list. 我宁愿不必单独调用以获取每个列表的根文件夹url。

Update: 更新:

I posted an answer below, but I feel like there is a better way out there somewhere. 我在下面发布了答案,但我觉得那里有更好的方法。 Feel free to post an answer if it's better than mine and I'll mark yours as the answer. 如果答案比我的要好,请随时发布答案,我会将您的答案标记为答案。

What you want to do is to check that the element exists before getting it's value because at the moment you are just assuming that they will always exist. 您想要做的是在获取元素值之前检查该元素是否存在,因为目前您只是假设它们将始终存在。

This has been asked before here (I haven't got enough reputation to post this as a comment): Check if an element exists when parsing XML 在此之前,有人问过这个问题(我没有足够的声誉来发表此评论): 解析XML时检查是否存在一个元素

I figured out a way to get me what I need but I feel like there has to be a better way... 我想出了一种方法来满足我的需要,但我觉得必须有更好的方法...

private readonly XNamespace a = "http://www.w3.org/2005/Atom";
private readonly XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
private readonly XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";

List<KLList> lists = doc.Descendants(a + "entry").Where(element => element.Attribute(m + "etag") != null).Select(
    list => new KLList()
    {
        Id = list.Descendants(d + "Id").FirstOrDefault().Value,
        Title = list.Descendants(d + "Title").FirstOrDefault().Value,
        ListItemEntityTypeFullName = list.Descendants(d + "ListItemEntityTypeFullName").FirstOrDefault().Value,
        BaseType = (BaseType)Convert.ToInt32(list.Descendants(d + "BaseType").FirstOrDefault().Value),
        ListTemplateType = (ListTemplateType)Convert.ToInt32(list.Descendants(d + "BaseTemplate").FirstOrDefault().Value),
        RelativeUrl = list.Descendants(d + "ServerRelativeUrl").FirstOrDefault().Value
    }).ToList();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM