【问题标题】:how to get specific nested values inside of XML using Linq to XML C# in .Net 5.0如何在 .Net 5.0 中使用 Linq to XML C# 在 XML 中获取特定的嵌套值
【发布时间】:2022-02-10 08:27:01
【问题描述】:

我正在处理从 Confluence 导出的大量 XML 文件,以表示给定 Confluence 空间的当前状态。对于熟悉 Confluence 的人来说,这用于在环境中或跨环境备份和恢复或迁移 Confluence 空间。

我正在尝试自动对 XML 进行一些基本分析,以便根据我们定义的一组规则输出一些有用的信息来确定我们的导出数据是否“正常”。

考虑到其中一些导出的大小和 XML 的结构,手动分析可能会很痛苦并且非常耗时。

基本上我已将 XML 缩减为“对象”XElements 的 IEnumerable

var filename = "export.xml";
var currentDirectory = Directory.GetCurrentDirectory();
var confluenceExportFilePath = Path.Combine(currentDirectory, filename);
XDocument confluenceExport = XDocument.Load(confluenceExportFilePath);
var objects = confluenceExport.Descendants("object");

然后我更进一步并且只选择了包含等于“页面”的类属性的对象,因为我只关心作为页面“对象”的“对象”。到目前为止,我已经返回了有关每个页面的一些基本“标题”信息。

var pages =
from page in objects
where (string)page.Attribute("class") == "Page"
select new Page
{
    Id = (string)page.Element("id"),
    Title = (string)page.Elements("property").FirstOrDefault(property => 
        property.Attribute("name").Value == "title"),
    Version = (int)page.Elements("property").FirstOrDefault(property => 
        property.Attribute("name").Value == "version"),
}; 

示例页面“对象”可能如下所示:

<object class="Page" package="com.atlassian.confluence.pages">
    <id name="id">001</id>
    <property name="title"><![CDATA[Test Page]]></property>
    <property name="lowerTitle"><![CDATA[test page]]></property>
    <property name="version">022</property>
    <property name="creationDate">2020-06-15 20:13:00.195</property>
    <property name="lastModificationDate">2020-06-18 12:01:04.482</property>
    <property name="versionComment"><![CDATA[]]></property>
    <collection name="bodyContents" class="java.util.Collection">
        <element class="BodyContent" package="com.atlassian.confluence.core">
            <id name="id">011</id>
        </element>
    </collection>
    <collection name="historicalVersions" class="java.util.Collection">
        <element class="Page" package="com.atlassian.confluence.pages">
            <id name="id">021</id>
        </element>
        <element class="Page" package="com.atlassian.confluence.pages">
            <id name="id">022</id>
        </element>
    </collection>
    <property name="contentStatus"><![CDATA[current]]></property>
    <collection name="attachments" class="java.util.Collection">
        <element class="Attachment" package="com.atlassian.confluence.pages">
            <id name="id">031</id>
        </element>
        <element class="Attachment" package="com.atlassian.confluence.pages">
            <id name="id">032</id>
        </element>
    </collection>
</object>

但是,我想更深入地研究 XML 并获得一些更具体的数据,但我正在努力做到这一点。例如,我想选择嵌套在 BodyContent 集合中的“id”值。

    <collection name="bodyContents" class="java.util.Collection">
        <element class="BodyContent" package="com.atlassian.confluence.core">
            <id name="id">011</id>
        </element>
    </collection>

最终我想要的是能够输出:

Page ID: 001
Page Title: Test Page
Page Version: 022
Page Body Content ID: 011

我怎样才能得到这个?

【问题讨论】:

  • 我很确定 Confluence 页面的数据可以导出为 JSON。这对你来说可能会更容易。
  • 我相信你是对的,但在这种情况下,我无法控制将导出数据交给我们的格式。在某些情况下,我们可能会收到 JSON,但我们必须能够处理 XML。

标签: c# xml linq-to-xml .net-5 confluence


【解决方案1】:

下面的代码使用class BodyContent 查找第一个element 并获取其id 子元素的值。对于您示例中的xml,这些搜索条件就足够了。

var pages =
    from page in objects
    where (string)page.Attribute("class") == "Page"
    select new Page
    {
        BodyContentId = 
            (string)page
                .Descendants("element")
                .Where(o => (string)o.Attribute("class") == "BodyContent")
                .FirstOrDefault()?.Element("id")
                
        // Other properties
    };

还为您提供指向 post 的指针,了解如何处理大型 xml 文件。
简而言之,使用XmlReader 循环页面上的&lt;object class="Page&gt; 元素,并且只为您应用上述Linq 语句的单个page 加载XElement/XDocument

【讨论】:

    【解决方案2】:

    如果你想深入挖掘,那么可以直接使用XPath来检索需要的值。

    代码sn-p:

    var docNav = new XPathDocument(FILE_PATH);
    var navigator = docNav.CreateNavigator();
    var nodeIterator = navigator.Select("//object");
    while (nodeIterator.MoveNext())
    {
        Console.WriteLine("Page ID: {0}", nodeIterator.Current.SelectSingleNode("id")?.Value);
        Console.WriteLine("Page Title: {0}", nodeIterator.Current.SelectSingleNode("property[@name='title']")?.Value);
        Console.WriteLine("Page Version: {0}", nodeIterator.Current.SelectSingleNode("property[@name='version']")?.Value);
        Console.WriteLine("Page Body Content ID: {0}", nodeIterator.Current.SelectSingleNode("collection[@name='bodyContents']//id")?.Value);
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-22
      相关资源
      最近更新 更多