5

我需要遍历书签开始和书签结束标记之间的节点。该问题似乎分解为树遍历,但我无法确定正确的算法。书签开始和结束元素是非复合节点(没有子节点),可能出现在树中的任意深度。书签开始也不能保证在相同的深度。

如果您为文档绘制树结构,我想检查开始和结束书签之间的所有节点。我认为一种算法可以遍历从节点 x 开始并在节点 y 结束的不平衡树。这听起来可行还是我错过了什么。

如果这是可行的,您能否指出可以完成返回节点的树遍历的方向?

4

2 回答 2

3

这取决于您想要做什么,但是,如果您主要对两个书签之间的文本感兴趣,那么这是 XmlDocument / XPath 语义比 LINQ to XML 或强类型对象模型更容易使用的情况之一开放 XML SDK V2。XPath 的“following::*”轴的语义是您想要的。下面的示例使用 XmlDocument 和 XPath 打印书签开始和结束之间的节点名称。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

class Program
{
    public static XmlDocument GetXmlDocument(OpenXmlPart part)
    {
        XmlDocument xmlDoc = new XmlDocument();
        using (Stream partStream = part.GetStream())
        using (XmlReader partXmlReader = XmlReader.Create(partStream))
            xmlDoc.Load(partXmlReader);
        return xmlDoc;
    }

    static void Main(string[] args)
    {
        using (WordprocessingDocument doc =
            WordprocessingDocument.Open("Test.docx", false))
        {
            XmlDocument xmlDoc = GetXmlDocument(doc.MainDocumentPart);
            string wordNamespace =
                "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
            XmlNamespaceManager nsmgr =
                new XmlNamespaceManager(xmlDoc.NameTable);
            nsmgr.AddNamespace("w", wordNamespace);
            XmlElement bookmarkStart = (XmlElement)xmlDoc.SelectSingleNode("descendant::w:bookmarkStart[@w:id='0']", nsmgr);
            XmlNodeList nodesFollowing = bookmarkStart.SelectNodes("following::*", nsmgr);
            var nodesBetween = nodesFollowing
                .Cast<XmlNode>()
                .TakeWhile(n =>
                    {
                        if (n.Name != "w:bookmarkEnd")
                            return true;
                        if (n.Attributes.Cast<XmlAttribute>().Any(a => a.Name == "w:id" && a.Value == "0"))
                            return false;
                        return true;
                    });
            foreach (XmlElement item in nodesBetween)
            {
                Console.WriteLine(item.Name);
                if (item.Name == "w:bookmarkStart" || item.Name == "w:bookmarkEnd")
                    foreach (XmlAttribute att in item.Attributes)
                        Console.WriteLine("{0}:{1}", att.Name, att.Value);
            }
        }
    }
}
于 2011-05-15T11:54:29.800 回答
1

我已经组合了一个可以轻松检索书签文本的算法。

如何从 OpenXML WordprocessingML 文档中检索书签的文本

我还编写了代码来替换书签的文本:

替换 OpenXML WordprocessingML 文档中书签的文本

-埃里克

于 2011-09-09T14:23:42.070 回答