/// <summary> /// Trys to create an OpenXmlElement from the specified namespace URI and local name. /// </summary> /// <param name="parent">The parent element.</param> /// <param name="fileFormat">The specified file format version.</param> /// <param name="namespaceUri">The namespace URI of the requested child element.</param> /// <param name="localName">The local name of the requested child element.</param> /// <returns>A new OpenXmlElement if the parent element can contains a child with the specified namespace and local name. Otherwise, returns null.</returns> internal static OpenXmlElement?TryCreateValidChild(this OpenXmlElement parent, FileFormatVersions fileFormat, string namespaceUri, string localName) { Debug.Assert(parent is OpenXmlCompositeElement); var newElement = parent.CreateElement(OpenXmlQualifiedName.Create(namespaceUri, string.Empty, localName)); if (newElement is OpenXmlUnknownElement || !newElement.IsInVersion(fileFormat)) { return(null); } return(newElement); }
/// <summary> /// Populates the XML into a strong typed DOM tree. /// </summary> /// <param name="xmlReader">The XmlReader to read the XML content.</param> /// <param name="loadMode">Specifies a load mode that is either lazy or full.</param> private protected override void Populate(XmlReader xmlReader, OpenXmlLoadMode loadMode) { LoadAttributes(xmlReader); if (!xmlReader.IsEmptyElement) { xmlReader.Read(); // read this element while (!xmlReader.EOF) { // O15:#3024890, OpenXmlCompositeElement ignores the Whitespace NodeType. if (xmlReader.NodeType == XmlNodeType.Whitespace) { xmlReader.Skip(); continue; } else if (xmlReader.NodeType == XmlNodeType.EndElement) { Debug.Assert(string.Equals(xmlReader.LocalName, LocalName, StringComparison.Ordinal)); xmlReader.Skip(); // move to next node break; } OpenXmlElement element = ElementFactory(xmlReader); // set parent before Load( ) call. AlternateContentChoice need parent info on loading. element.Parent = this; bool isACB = element is AlternateContent; if (isACB && element.OpenXmlElementContext is not null) { element.OpenXmlElementContext.ACBlockLevel++; } bool mcContextPushed = false; if (!(element is OpenXmlMiscNode)) { // push MC context based on the context of the child element to be loaded mcContextPushed = PushMcContext(xmlReader); } //Process the element according to the MC behavior var action = ElementAction.Normal; if (OpenXmlElementContext is not null && OpenXmlElementContext.MCSettings.ProcessMode != DocumentFormat.OpenXml.Packaging.MarkupCompatibilityProcessMode.NoProcess) { action = OpenXmlElementContext.MCContext.GetElementAction(element, OpenXmlElementContext.MCSettings.TargetFileFormatVersions); } element.Load(xmlReader, loadMode); if (mcContextPushed) { PopMcContext(); } if (isACB && element.OpenXmlElementContext is not null) { element.OpenXmlElementContext.ACBlockLevel--; } switch (action) { case ElementAction.Normal: { AddANode(element); break; } case ElementAction.Ignore: { element.Parent = null; continue; } case ElementAction.ProcessContent: { element.Parent = null; while (element.ChildElements.Count > 0) { if (element.FirstChild is not OpenXmlElement node) { break; } node.Remove(); var newnode = default(OpenXmlElement); // If node is an UnknowElement, we should try to see whether the parent element can load the node as strong typed element if (node is OpenXmlUnknownElement) { newnode = CreateElement(OpenXmlQualifiedName.Create(node.NamespaceUri, node.Prefix, node.LocalName)); if (!(newnode is OpenXmlUnknownElement)) { // The following method will load teh element in MCMode.Full // since the node is already MC-processed when loading as unknown type, full loading the outerXml is fine newnode.OuterXml = node.OuterXml; // unnecessary xmlns attribute will be added, remove it. RemoveUnnecessaryExtAttr(node, newnode); } else { newnode = null; } } if (newnode is not null) { AddANode(newnode); } else { //append the original node AddANode(node); } } break; } case ElementAction.ACBlock: { if (element is not AlternateContent acb) { break; } var effectiveNode = OpenXmlElementContext?.MCContext.GetContentFromACBlock(acb, OpenXmlElementContext.MCSettings.TargetFileFormatVersions); if (effectiveNode is null) { break; } element.Parent = null; effectiveNode.Parent = null; while (effectiveNode.FirstChild is not null) { var node = effectiveNode.FirstChild; node.Remove(); AddANode(node); node.CheckMustUnderstandAttr(); } break; } } } } else { xmlReader.Skip(); } // Set raw outer xml to empty to indicate that it passed RawOuterXml = string.Empty; }