internal static void BuildSubtree(XmlReader reader, XmlWriter writer) { // important (perf) string literal... string xmlnsUri = XmlConst.ReservedNsXmlNs; // http://www.w3.org/2000/xmlns/ ReadState readState = reader.ReadState; if (readState != ReadState.Initial && readState != ReadState.Interactive) { throw new ArgumentException(SR.Xml_InvalidOperation, "reader"); } int level = 0; if (readState == ReadState.Initial) { if (!reader.Read()) return; level++; // if start in initial, read everything (not just first) } do { switch (reader.NodeType) { case XmlNodeType.Element: writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI); bool isEmptyElement = reader.IsEmptyElement; while (reader.MoveToNextAttribute()) { if ((object)reader.NamespaceURI == (object)xmlnsUri) { if (reader.Prefix.Length == 0) { // Default namespace declaration "xmlns" Debug.Assert(reader.LocalName == "xmlns"); writer.WriteAttributeString("", "xmlns", xmlnsUri, reader.Value); } else { Debug.Assert(reader.Prefix == "xmlns"); writer.WriteAttributeString("xmlns", reader.LocalName, xmlnsUri, reader.Value); } } else { writer.WriteStartAttribute(reader.Prefix, reader.LocalName, reader.NamespaceURI); writer.WriteString(reader.Value); writer.WriteEndAttribute(); } } reader.MoveToElement(); if (isEmptyElement) { // there might still be a value, if there is a default value specified in the schema writer.WriteEndElement(); } else { level++; } break; case XmlNodeType.EndElement: writer.WriteFullEndElement(); //should not read beyond the level of the reader's original position. level--; break; case XmlNodeType.Text: case XmlNodeType.CDATA: writer.WriteString(reader.Value); break; case XmlNodeType.SignificantWhitespace: case XmlNodeType.Whitespace: writer.WriteString(reader.Value); break; case XmlNodeType.Comment: writer.WriteComment(reader.Value); break; case XmlNodeType.ProcessingInstruction: writer.WriteProcessingInstruction(reader.LocalName, reader.Value); break; case XmlNodeType.EntityReference: reader.ResolveEntity(); break; case XmlNodeType.EndEntity: case XmlNodeType.None: case XmlNodeType.DocumentType: case XmlNodeType.XmlDeclaration: break; case XmlNodeType.Attribute: if ((object)reader.NamespaceURI == (object)xmlnsUri) { if (reader.Prefix.Length == 0) { // Default namespace declaration "xmlns" Debug.Assert(reader.LocalName == "xmlns"); writer.WriteAttributeString("", "xmlns", xmlnsUri, reader.Value); } else { Debug.Assert(reader.Prefix == "xmlns"); writer.WriteAttributeString("xmlns", reader.LocalName, xmlnsUri, reader.Value); } } else { writer.WriteStartAttribute(reader.Prefix, reader.LocalName, reader.NamespaceURI); writer.WriteString(reader.Value); writer.WriteEndAttribute(); } break; } } while (reader.Read() && (level > 0)); }
/// <summary> /// Create a writer that can be used to create nodes in this document. The root node will be assigned "baseUri", and flags /// can be passed to indicate that names should be atomized by the builder and/or a fragment should be created. /// </summary> internal void LoadFromReader(XmlReader reader, XmlSpace space) { XPathDocumentBuilder builder; IXmlLineInfo lineInfo; string xmlnsUri; bool topLevelReader; int initialDepth; if (reader == null) throw new ArgumentNullException(nameof(reader)); // Determine line number provider lineInfo = reader as IXmlLineInfo; if (lineInfo == null || !lineInfo.HasLineInfo()) lineInfo = null; _hasLineInfo = (lineInfo != null); _nameTable = reader.NameTable; builder = new XPathDocumentBuilder(this, lineInfo, reader.BaseURI, LoadFlags.None); try { // Determine whether reader is in initial state topLevelReader = (reader.ReadState == ReadState.Initial); initialDepth = reader.Depth; // Get atomized xmlns uri Debug.Assert((object)_nameTable.Get(string.Empty) == (object)string.Empty, "NameTable must contain atomized string.Empty"); xmlnsUri = _nameTable.Get(XmlReservedNs.NsXmlNs); // Read past Initial state; if there are no more events then load is complete if (topLevelReader && !reader.Read()) return; // Read all events do { // If reader began in intermediate state, return when all siblings have been read if (!topLevelReader && reader.Depth < initialDepth) return; switch (reader.NodeType) { case XmlNodeType.Element: { bool isEmptyElement = reader.IsEmptyElement; builder.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.BaseURI); // Add attribute and namespace nodes to element while (reader.MoveToNextAttribute()) { string namespaceUri = reader.NamespaceURI; if ((object)namespaceUri == (object)xmlnsUri) { if (reader.Prefix.Length == 0) { // Default namespace declaration "xmlns" Debug.Assert(reader.LocalName == "xmlns"); builder.WriteNamespaceDeclaration(string.Empty, reader.Value); } else { Debug.Assert(reader.Prefix == "xmlns"); builder.WriteNamespaceDeclaration(reader.LocalName, reader.Value); } } else { builder.WriteStartAttribute(reader.Prefix, reader.LocalName, namespaceUri); builder.WriteString(reader.Value, TextBlockType.Text); builder.WriteEndAttribute(); } } if (isEmptyElement) builder.WriteEndElement(true); break; } case XmlNodeType.EndElement: builder.WriteEndElement(false); break; case XmlNodeType.Text: case XmlNodeType.CDATA: builder.WriteString(reader.Value, TextBlockType.Text); break; case XmlNodeType.SignificantWhitespace: if (reader.XmlSpace == XmlSpace.Preserve) builder.WriteString(reader.Value, TextBlockType.SignificantWhitespace); else // Significant whitespace without xml:space="preserve" is not significant in XPath/XQuery data model goto case XmlNodeType.Whitespace; break; case XmlNodeType.Whitespace: // We intentionally ignore the reader.XmlSpace property here and blindly trust // the reported node type. If the reported information is not in sync // (in this case if the reader.XmlSpace == Preserve) then we make the choice // to trust the reported node type. Since we have no control over the input reader // we can't even assert here. // Always filter top-level whitespace if (space == XmlSpace.Preserve && (!topLevelReader || reader.Depth != 0)) builder.WriteString(reader.Value, TextBlockType.Whitespace); break; case XmlNodeType.Comment: builder.WriteComment(reader.Value); break; case XmlNodeType.ProcessingInstruction: builder.WriteProcessingInstruction(reader.LocalName, reader.Value, reader.BaseURI); break; case XmlNodeType.EntityReference: reader.ResolveEntity(); break; case XmlNodeType.DocumentType: // Create ID tables IDtdInfo info = reader.DtdInfo; if (info != null) builder.CreateIdTables(info); break; case XmlNodeType.EndEntity: case XmlNodeType.None: case XmlNodeType.XmlDeclaration: break; } } while (reader.Read()); } finally { builder.Close(); } }
private void ReadChildNodes( XPathContainer parent, string parentBaseUri, XmlReader reader, PositionInfo positionInfo ) { do { documentIndex++; switch( reader.NodeType ) { case XmlNodeType.Element: { string baseUri = reader.BaseURI; XPathElement e = null; if( reader.IsEmptyElement ) { e = new XPathEmptyElement( reader.Prefix, reader.LocalName, reader.NamespaceURI, positionInfo.LineNumber, positionInfo.LinePosition, parent.topNamespace, documentIndex ); ReadAttributes( e, reader ); } else { e = new XPathElement( reader.Prefix, reader.LocalName, reader.NamespaceURI, positionInfo.LineNumber, positionInfo.LinePosition, parent.topNamespace, documentIndex ); ReadAttributes( e, reader ); reader.Read(); ReadChildNodes( e, baseUri, reader, positionInfo ); } if (parentBaseUri != baseUri) { // We can't user Ref.Equial Because Reader fails to fully atomize base Uri. if (elementBaseUriMap == null) { elementBaseUriMap = new Hashtable(); } elementBaseUriMap[e] = baseUri; } parent.AppendChild( e ); break; } case XmlNodeType.Comment: parent.AppendChild( new XPathComment( reader.Value, documentIndex ) ); break; case XmlNodeType.ProcessingInstruction: parent.AppendChild( new XPathProcessingInstruction( reader.LocalName, reader.Value, documentIndex ) ); break; case XmlNodeType.SignificantWhitespace: if( reader.XmlSpace == XmlSpace.Preserve ) { parent.AppendSignificantWhitespace( reader.Value, positionInfo.LineNumber, positionInfo.LinePosition, documentIndex ); } else { // SWS without xml:space='preserve' is not really significant for XPath. // so we treat it as just WS goto case XmlNodeType.Whitespace; } break; case XmlNodeType.Whitespace: if( space == XmlSpace.Preserve ) { parent.AppendWhitespace( reader.Value, positionInfo.LineNumber, positionInfo.LinePosition, documentIndex ); } break; case XmlNodeType.CDATA: case XmlNodeType.Text: parent.AppendText( reader.Value, positionInfo.LineNumber, positionInfo.LinePosition, documentIndex ); break; case XmlNodeType.EntityReference: reader.ResolveEntity(); reader.Read(); ReadChildNodes( parent, parentBaseUri, reader, positionInfo); break; case XmlNodeType.EndEntity: case XmlNodeType.EndElement: case XmlNodeType.None: return; case XmlNodeType.DocumentType: XmlValidatingReader vr = reader as XmlValidatingReader; if ( vr != null ) { SchemaInfo info = vr.GetSchemaInfo(); if ( info != null ) { GetIDInfo( info); } } break; case XmlNodeType.XmlDeclaration: default: break; } }while( reader.Read() ); }