在CommentRangeStart和CommentRangeEnd之间获取OpenXmlElements

时间:2012-08-29 10:06:41

标签: c# openxml openxml-sdk

我要做的是在CommentRangeStart和相应的CommentRangeEnd之间找到OpenXMLElements。

我尝试了两种方法来实现这一点,但问题是CommentRangeEnd不需要与开始处于同一级别。它可以嵌套在子元素中,看下面非常简单的结构(注意这是不正确的,打开xml只是为了显示一般的想法)。

<w:commentstart/>
<w:paragraph>
  <w:run />
  <w:commentend />
</w:paragraph>

我尝试过的两件事如下: 第一:我写了一个枚举,它返回项目直到结束

public static IEnumerable<OpenXmlElement> SiblingsUntilCommentRangeEnd(CommentRangeStart commentStart)
{
    OpenXmlElement element = commentStart.NextSibling();

    if (IsMatchingCommentEnd(element, commentStart.Id.Value))
    {
        yield break;
    }

    while (true)
    { 
        yield return element;
        element = element.NextSibling();

        // Check that the item 
        if (element == null)
        {
            yield break;
        }

        if (IsMatchingCommentEnd(element, commentStart.Id.Value))
        {
            yield break;
        }
    }
}

public static bool IsMatchingCommentEnd(OpenXmlElement element, string commentId)
{
    CommentRangeEnd commentEnd = element as CommentRangeEnd;
    if (commentEnd != null)
    {
        return commentEnd.Id == commentId;
    }
    return false;
}

第二:然后意识到开始和结束不在同一水平的问题我继续寻找并且我发现Eric Whites answer for dealing with elements between bookmark elements我复古适合我的例子,但仍然是开始和结束的问题拥有相同的父级(即在同一级别)是一个问题,我无法使用它。

有没有更好的方法来看待这个我正在寻找一种处理元素的方法,因为我需要使用正在评论的文本。

修改 澄清我想要实现的目标: 我正在使用文字编辑的文档和文档中的注释我希望获得在特定注释ID的开始和结束范围之间评论的文本。

编辑2: 我已经提出了我目前正在考虑的工作版本,但我的问题是它可能因为Word中的不同用户组合而非常脆弱。这也适用于xml,这不是一个真正的问题但可能希望更改为OpenXML SDK。目前看起来我需要解析整个文档来获取我需要的项目而不是使用1个特定注释。 https://github.com/mhbuck/DocumentCommentParser/

遇到的主要问题:CommentRangeStartCommentRangeEnd可以位于XML文档中的不同嵌套中。根节点可能是唯一类似的祖先元素。

1 个答案:

答案 0 :(得分:3)

您可以尝试使用Descendants<T>()方法枚举给定类型的节点的所有后代。所以,你的代码看起来与此类似(我在不使用yeld的情况下编写它以使其更具可读性;)):

public static IEnumerable<OpenXmlElement> SiblingsUntilCommentRangeEnd(CommentRangeStart commentStart)
{
    List<OpenXmlElement> commentedNodes = new List<OpenXmlElement>();

    OpenXmlElement element = commentStart;

    while (true)
    {
        element = element.NextSibling();

        // check that the item exists
        if (element == null)
        {
            break;
        }

        //check that the item is matching comment end
        if (IsMatchingCommentEnd(element, commentStart.Id.Value))
        {
            break;
        }

        //check that there is a matching element in the current element's descendants
        var descendantsCommentEnd = element.Descendants<CommentRangeEnd>();
        if (descendantsCommentEnd != null)
        {
            foreach (CommentRangeEnd rangeEndNode in descendantsCommentEnd)
            {
                if (IsMatchingCommentEnd(rangeEndNode, commentStart.Id.Value))
                {
                    //matching range end element found in current element's descendants
                    //an improvement could be made here to manually select descendants before CommentRangeEnd node
                    break;
                }
            }
        }

        commentedNodes.Add(element);
    }

    return commentedNodes;
}

正如其中一条评论所标记的那样,如果它在当前元素的后代中找到CommentRangeEnd元素,它现在就结束了。

我还没有测试过这段代码,所以如果你有任何问题,请在评论中告诉我。

请注意,如果start元素在文档层次结构中比end元素更深,则此方法将不起作用。在某些情况下,它也不会返回评论中的一些内容。如果您需要它,我可以稍后使用替代解决方案更新答案来处理这种情况。还请解释为什么需要找到这些评论,因为可能会使用替代方法。