我需要能够获取WordML文档,并通过其标题将其转换为对象图,该标题将通过web应用程序转换为可导航结构。这可以类似于";导航";窗格。
以下是我需要将Word文档放入的对象结构的一个简单示例:
public class Folder
{
public string Name { get; set; }
public string Description { get; set; }
public Folder ParentFolder { get; set; }
public ICollection<Folder> Subfolders { get; set; }
public ICollection<Page> Pages { get; set; }
}
public class Page
{
public string Title { get; set; }
public string Content { get; set; }
public Folder ContainingFolder { get; set; }
}
希望这是不言自明的。它基本上就像一个基本的文件系统。
Word文档可以有多个部分,其中包含任意数量的嵌套标题。如果我们把标题结构看作一棵树,我需要每一片叶子(一个没有副标题的标题部分)都是一个页面,每一个分支都是一个子文件夹。例如:
标题1(a)
部分内容(1)
标题2(b)
标题3(c)
部分内容(2)
标题2(d)
标题3(e)
部分内容(3)
标题3(f)
部分内容(4)
标题4(g)部分内容(5)
在本例中,(a)将成为新文件夹的名称,(1)为描述,并具有子文件夹(b)和(d),每个子文件夹都将具有空描述。由于(c)没有副标题,因此它将成为标题为(c)、内容为(2)、包含文件夹为(b)的页面。与(e)和(3)相同。(f) 应成为ParentFolder(d)下的新文件夹,说明为(4),以及(g)的新页面,标题为(g),内容为(5)。
我希望我还没有失去你。
到目前为止,我已经尝试过用OpenXMLSDK打开一个文档,但由于处理结果XML有点麻烦,我决定使用库将文档转换为HTML。这提供了一个漂亮、干净的文档,我可以使用LINQ to XML遍历它。
现在我有了一个带有p、h1、h2等标记的平面HTML文档,但很明显,它们不是嵌套的;他们都是兄弟姐妹。如何遍历此文档并将每个标题部分转换为我上面解释的对象图?
需要注意的是:文档可能不总是以H1开头,子标题也可能不总是下一个直接的子标题(例如,H2后面跟着H4)。如果最高级的标题在文档的中间,我们可以忽略它之前的任何内容。
好吧,我想明白了。我还没有测试所有的病例,就像我在问题结尾的警告中提到的那样,但目前,它会起作用。如果有人偶然发现并感兴趣,下面是我所做的。
首先,我最终将Word文档转换为HTML,然后使用LINQ到XML对其进行解析。该方法首先通过传入HTML中的第一个带标题标记的元素("H1"、"H2"等)和一个Folder对象来调用,该对象将包含我在问题中描述的Word到Folder/Page结构的输出。
private Folder ConvertHtmlHeadersToFolderStructure(XElement header, Folder containingFolder)
{
// Extract the usable data from the element
// header.Value
string title;
// header.NextNode.ToString() for everything between this and the next header element
StringBuilder contentSb;
ExtractInfo(header, out title, out contentSb);
// Determine if this header element is going to be a page or a folder
// It's a page if the current header element number is greater than or equal to
// the next header element number, e.g. h3 >= h2; h3 is a page
XElement nextHeader;
if (IsElementALeaf(header, out nextHeader))
{
containingFolder.Pages.Add(new Page
{
Content = contentSb.ToString(),
Title = title,
Folder = containingFolder
});
if (nextHeader != null)
{
int thisHeaderLevel = GetHeaderLevel(header);
int nextHeaderLevel = GetHeaderLevel(nextHeader);
Folder upLevelFolder = containingFolder;
for (int i = 0; i < thisHeaderLevel - nextHeaderLevel; i++)
{
upLevelFolder = upLevelFolder.ParentFolder;
}
ConvertHtmlHeadersToFolderStructure(nextHeader, upLevelFolder);
}
return containingFolder;
}
else
{
Folder subFolder = new Folder
{
Description = contentSb.ToString(),
Name = title,
ParentFolder = containingFolder
};
// nextHeader shouldn't be null if we got here
subFolder = ConvertHtmlHeadersToFolderStructure(nextHeader, subFolder);
containingFolder.Subfolders.Add(subFolder);
return containingFolder;
}
}