Ejemplo n.º 1
0
        private static IEnumerable <OpenXmlElement> ValidatingTraverse(OpenXmlElement inElement, MCContext mcContext, FileFormatVersions version)
        {
            var stack = new Stack <OpenXmlElement>();

            stack.Push(inElement);

            while (stack.Count > 0)
            {
                var element = stack.Pop();

                if (element is null)
                {
                    mcContext.PopMCAttributes2();
                    continue;
                }

                // 1. Skip elements in ProcessContent.
                // 2. Select correct Choice / Fallback
                // Need bookkeep MC context
                // Need to collect MC context from ancestor

                // bookkeep MC context,
                // MC Spec: Compatibility-rule attributes shall affect the element to which they 1 are attached, including the element’s other attributes and contents.
                mcContext.PushMCAttributes2(element.MCAttributes, element.LookupNamespace);
                stack.Push(null);

                if (element.IsStrongTypedElement())
                {
                    // only call validate on elements that defined in the format.
                    if (version.AtLeast(element.InitialVersion))
                    {
                        yield return(element);
                    }
                    else if (mcContext.IsProcessContent(element))
                    {
                        // do not validate this element.
                    }

                    foreach (var child in element.ChildElements)
                    {
                        stack.Push(child);
                    }
                }
                else if (element.IsUnknown())
                {
                    // TODO: Issue: all types are weak types now, need to change the Framework to load strong typed elements!!!
                    if (mcContext.IsProcessContent(element))
                    {
                        // do validating on children elements.
                        foreach (var child in element.ChildElements)
                        {
                            stack.Push(child);
                        }
                    }
                }
                else if (element.IsAlternateContent())
                {
                    yield return(element);

                    var selectedContent = mcContext.GetContentFromACBlock((AlternateContent)element, version);

                    if (selectedContent is not null)
                    {
                        foreach (var child in selectedContent.ChildElements)
                        {
                            stack.Push(child);
                        }
                    }
                }
                else if (element.IsMiscNode())
                {
                    // non-element node
                    // just skip
                }
                else
                {
                    Debug.Assert(element is AlternateContentChoice || element is AlternateContentFallback);
                    Debug.Assert(element.Parent is not null && element.Parent is AlternateContent);

                    // should not be here, otherwise, wrong case ( the parent is not AlternateContent).
                }
            }
        }
        private static OpenXmlElement GetChildMc(this OpenXmlElement parent, OpenXmlElement child, MCContext mcContext, FileFormatVersions format)
        {
            // Use stack to cache the next siblings in different levels.
            Stack <OpenXmlElement> nextSiblings = new Stack <OpenXmlElement>();

            while (child != null)
            {
                var acb = child as AlternateContent;
                if (acb == null && child.IsInVersion(format))
                {
                    return(child);
                }
                else
                {
                    mcContext.PushMCAttributes2(child.MCAttributes, child.LookupNamespace);
                    if (acb != null)
                    {
                        nextSiblings.Push(child.GetNextNonMiscElementSibling());
                        var select = mcContext.GetContentFromACBlock(acb, format);
                        if (select != null)
                        {
                            child = select.GetFirstNonMiscElementChild();
                        }
                        else
                        {
                            // The ACB has no children elements.
                            // case like: <acb/> <acb><choice/><fallback/></acb>
                            child = null;
                        }
                    }
                    else
                    {
                        // Ignorable element, skip it
                        if (mcContext.IsIgnorableNs(child.NamespaceUri))
                        {
                            // Any element marked with ProcessContent should be an Ignorable Element
                            if (mcContext.IsProcessContent(child))
                            {
                                nextSiblings.Push(child.GetNextNonMiscElementSibling());
                                //
                                child = child.GetFirstNonMiscElementChild();
                            }
                            else
                            {
                                child = child.GetNextNonMiscElementSibling();
                            }
                        }
                        else
                        {
                            mcContext.PopMCAttributes2();
                            return(child);
                        }
                    }
                    mcContext.PopMCAttributes2();
                }

                while (child == null && nextSiblings.Count > 0)
                {
                    child = nextSiblings.Pop();
                }
            }

            // child is null.
            return(child);
        }