如何在.Net 5.0中使用Linq to XML C#获取XML内部的特定嵌套值



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

我正在尝试自动化对XML的一些基本分析,这样我就可以输出一些有用的信息来确定我们的导出数据是否是";OK";基于我们定义的一组规则。

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

从本质上讲,我已经将XML缩减为CCD_;对象";XElements.

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

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

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,并获得一些更具体的数据,我正在努力做到这一点。例如,我想选择";id";嵌套在BodyContent集合中的值。

<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

我该怎么办?

下面的代码查找具有classBodyContent的第一个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
};

还为您提供了一个关于如何处理大型xml文件的帖子指针
简而言之,使用XmlReader在页面IEnumerable0元素上循环,并仅为应用上述Linq语句的单个page加载XElement/XDocument

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

代码片段:

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

相关内容

  • 没有找到相关文章