我正在处理一个从Confluence导出的巨大XML文件,该文件表示给定Confluence空间的当前状态。对于熟悉Confluence的人来说,它用于在环境中或跨环境备份、恢复或迁移Confluence空间。
我正在尝试自动化对XML的一些基本分析,这样我就可以输出一些有用的信息来确定我们的导出数据是否是";OK";基于我们定义的一组规则。
考虑到其中一些导出的大小和XML的结构,手动分析可能会非常痛苦和耗时。
从本质上讲,我已经将XML缩减为CCD_;对象";XElement
s.
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
我该怎么办?
下面的代码查找具有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
};
还为您提供了一个关于如何处理大型xml
文件的帖子指针
简而言之,使用XmlReader
在页面IEnumerable
0元素上循环,并仅为应用上述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);
};