private bool ReadRoot() { Debug.Assert(_elementState == ElementState.Null); Debug.Assert(_elementStack.Count == 0); // TODO: should we take care of entity? <!DOCTYPE page [ <!ENTITY company "Microsoft"> ]> // TODO: is it OK that we skip all prolog ( DOCTYPE, Comment, PT ) ? _xmlReader.MoveToContent(); while (!_xmlReader.EOF && _xmlReader.NodeType != XmlNodeType.Element) { _xmlReader.Skip(); } if (_xmlReader.EOF || !_xmlReader.IsStartElement()) { throw new InvalidDataException(ExceptionMessages.PartIsEmpty); } // create the root element object OpenXmlElement rootElement = RootElementFactory.CreateElement(_xmlReader.NamespaceURI, _xmlReader.LocalName); if (rootElement == null) { throw new InvalidDataException(ExceptionMessages.PartUnknown); } _elementStack.Push(rootElement); LoadAttributes(); if (_xmlReader.IsEmptyElement) { _elementState = ElementState.LeafStart; rootElement.Load(_xmlReader, OpenXmlLoadMode.Full); } else { _elementState = ElementState.Start; } return(true); }
/// <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, OpenXmlCompositElement ignores the Whitespace NodeType. if (xmlReader.NodeType == XmlNodeType.Whitespace) { xmlReader.Skip(); continue; } else if (xmlReader.NodeType == XmlNodeType.EndElement) { Debug.Assert(xmlReader.LocalName.Equals(LocalName)); 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 != 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 != 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 != 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) { var node = element.FirstChild; node.Remove(); OpenXmlElement newnode = null; // 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 = ElementFactory(node.Prefix, node.LocalName, node.NamespaceUri); 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 != null) { AddANode(newnode); } else { //append the orignal node AddANode(node); } } break; } case ElementAction.ACBlock: { var effectiveNode = OpenXmlElementContext.MCContext.GetContentFromACBlock(element as AlternateContent, OpenXmlElementContext.MCSettings.TargetFileFormatVersions); if (effectiveNode == null) { break; } element.Parent = null; effectiveNode.Parent = null; while (effectiveNode.FirstChild != 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; }
//internal override void Load(XmlReader xmlReader) //{ // LoadAttributes(xmlReader); // this.Text = xmlReader.ReadElementString(); //} internal override void Populate(XmlReader xmlReader, OpenXmlLoadMode loadMode) { LoadAttributes(xmlReader); if (!xmlReader.IsEmptyElement) { // only when element is not empty (not <element />). xmlReader.Read(); // read this element this.RawInnerText = string.Empty; int unwanted = 0; int textNodePosition = -1; // the position of the text in the ShadowElement's children when there are other unexpected node. XmlNodeType textNodeType = XmlNodeType.Text; if (xmlReader.NodeType == XmlNodeType.EndElement) { Debug.Assert(xmlReader.LocalName.Equals(this.LocalName)); } else { while (!xmlReader.EOF) { if (xmlReader.NodeType == XmlNodeType.EndElement) { Debug.Assert(xmlReader.LocalName.Equals(this.LocalName)); break; } else if (string.IsNullOrEmpty(this.RawInnerText) && (xmlReader.NodeType == XmlNodeType.Text || xmlReader.NodeType == XmlNodeType.CDATA || xmlReader.NodeType == XmlNodeType.SignificantWhitespace || xmlReader.NodeType == XmlNodeType.Whitespace /* O15:#3024890 */)) { // text or CDATA // scenario: normal text element <Application>Microsoft Office Word</Application> // scenario: <w:t>This is <![CDATA[Xml Example <tag>text</tag>.]]> 1</w:t> // only load text when no text is loaded, // for case "<foo/>Text1<bar/>Text2", only load "Text1", very rare case this.RawInnerText = xmlReader.Value; textNodePosition = unwanted; textNodeType = xmlReader.NodeType; xmlReader.Read(); } else { Debug.Assert(xmlReader.NodeType != XmlNodeType.EntityReference); // Load unexpected children if there are any. OpenXmlElement child = this.ElementFactory(xmlReader); child.Load(xmlReader, OpenXmlLoadMode.Full); unwanted++; if (this.ShadowElement == null) { this.ShadowElement = new OpenXmlUnknownElement(this.Prefix, this.LocalName, this.NamespaceUri); } this.ShadowElement.AppendChild(child); } } } if (unwanted == 0) { // only text node, no unwanted children Debug.Assert(this.ShadowElement == null); } else if (textNodePosition > -1) { // place an OpenXmlMiscNode for the loaded text in the ShadowElement so that we can write out correct content in serialization. OpenXmlMiscNode textNode = null; switch (textNodeType) { case XmlNodeType.Text: textNode = OpenXmlMiscNode.CreateFromText(this.RawInnerText); break; case XmlNodeType.CDATA: textNode = OpenXmlMiscNode.CreateFromCdata(this.RawInnerText); break; case XmlNodeType.SignificantWhitespace: case XmlNodeType.Whitespace: /* O15:#3024890 */ textNode = OpenXmlMiscNode.CreateFromSignificantWhitespace(this.RawInnerText); break; } this.ShadowElement.InsertAt(textNode, textNodePosition); } else { // textNodePosition == -1, no text loaded. } } xmlReader.Skip(); // skip the end tag // set raw outer xml to empty to indicate that it is passed this.RawOuterXml = string.Empty; }