【问题标题】:How to parse XML using c# and XDocument into an object when multiple elements have the same name?当多个元素具有相同名称时,如何使用 c# 和 XDocument 将 XML 解析为一个对象?
【发布时间】:2014-03-20 05:43:09
【问题描述】:

我正在使用 SharePoint 2013 的 REST API 来解析 XML,但我无法解析特定的 XML 块。这是我可能会返回的一些 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>

我可以使用 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();

当我展开查询以获取列表根文件夹的服务器相对 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>

我尝试使用基本相同的代码,因为我希望 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();

但这不再有效。 doc.Descendants(m + "properties") 返回的第一件事是

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

因此尝试同时设置其他属性会引发对象引用异常,因为其他元素不在这里。

如何解析这个 XML 以便我想要的所有值都进入一个对象?我宁愿不必单独调用来获取每个列表的根文件夹 url。

更新:

我在下面发布了一个答案,但我觉得在某个地方有更好的方法。如果它比我的更好,请随时发布答案,我会将您的答案标记为答案。

【问题讨论】:

    标签: c# xml sharepoint


    【解决方案1】:

    我想出了一种方法来得到我需要的东西,但我觉得必须有更好的方法......

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

    【讨论】:

      【解决方案2】:

      您要做的是在获取它的值之前检查该元素是否存在,因为此时您只是假设它们将永远存在。

      这里之前已经问过这个问题(我没有足够的声誉来发表评论): Check if an element exists when parsing XML

      【讨论】:

      • 但是即使检查这些元素是否存在也不会得到我想要的。我想要的所有这些值都存在于&lt;entry /&gt; 下,但它们由&lt;m:properties /&gt; 的两个元素分隔。我想要两个&lt;m:properties /&gt; 下的所有东西都在一个对象中。目前,遍历doc.Descendants(m + "properties") 将它们分开,这不是我想要的。这有意义吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-23
      • 1970-01-01
      • 2013-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多