System.Configuration.XmlUtil.CopyXmlNode C# (CSharp) Method

CopyXmlNode() private method

private CopyXmlNode ( XmlUtilWriter utilWriter ) : bool
utilWriter XmlUtilWriter
return bool
        internal bool CopyXmlNode(XmlUtilWriter utilWriter) {
            //
            // For nodes that have a closing string, such as "<element  >"
            // the XmlReader API does not give us the location of the closing string, e.g. ">".
            // To correctly determine the location of the closing part, we advance the reader,
            // determine the position of the next node, then work backwards to add whitespace
            // and add the closing string.
            //
            string close = null;
            int lineNumber = -1;
            int linePosition = -1;

            int readerLineNumber = 0;
            int readerLinePosition = 0;
            int writerLineNumber = 0;
            int writerLinePosition = 0;
            if (utilWriter.TrackPosition) {
                readerLineNumber = _reader.LineNumber;
                readerLinePosition = _reader.LinePosition;
                writerLineNumber = utilWriter.LineNumber;
                writerLinePosition = utilWriter.LinePosition;
            }

            // We test the node type in the likely order of decreasing occurrence.
            XmlNodeType nodeType = _reader.NodeType;
            if (nodeType == XmlNodeType.Whitespace) {
                utilWriter.Write(_reader.Value);
            }
            else if (nodeType == XmlNodeType.Element) {
                close = (_reader.IsEmptyElement) ? "/>" : ">";

                // get the line position after the element declaration:
                //      <element    attr="value"
                //              ^
                //              linePosition
                //
                lineNumber = _reader.LineNumber;
                linePosition = _reader.LinePosition + _reader.Name.Length;

                utilWriter.Write('<');
                utilWriter.Write(_reader.Name);

                //
                // Note that there is no way to get spacing between attribute name and value
                // For example:
                //
                //          <elem attr="value" />
                //
                // is reported with the same position as
                //
                //          <elem attr = "value" />
                //
                // The first example has no spaces around '=', the second example does.
                //
                while (_reader.MoveToNextAttribute()) {
                    // get line position of the attribute declaration
                    //      <element attr="value"
                    //               ^
                    //               attrLinePosition
                    //
                    int attrLineNumber = _reader.LineNumber;
                    int attrLinePosition = _reader.LinePosition;

                    // Write the whitespace before the attribute
                    utilWriter.AppendRequiredWhiteSpace(lineNumber, linePosition, attrLineNumber, attrLinePosition);

                    // Write the attribute and value
                    int charactersWritten = utilWriter.Write(_reader.Name);
                    charactersWritten += utilWriter.Write('=');
                    charactersWritten += utilWriter.AppendAttributeValue(_reader);

                    // Update position. Note that the attribute value is escaped to always be on a single line.
                    lineNumber = attrLineNumber;
                    linePosition = attrLinePosition + charactersWritten;
                }
            }
            else if (nodeType == XmlNodeType.EndElement) {
                close = ">";

                // get line position after the end element declaration:
                //      </element    >
                //               ^
                //               linePosition
                //
                lineNumber = _reader.LineNumber;
                linePosition = _reader.LinePosition + _reader.Name.Length;

                utilWriter.Write("</");
                utilWriter.Write(_reader.Name);
            }
            else if (nodeType == XmlNodeType.Comment) {
                utilWriter.AppendComment(_reader.Value);
            }
            else if (nodeType == XmlNodeType.Text) {
                utilWriter.AppendEscapeTextString(_reader.Value);
            }
            else if (nodeType == XmlNodeType.XmlDeclaration) {
                close = "?>";

                // get line position after the xml declaration:
                //      <?xml    version="1.0"
                //           ^
                //           linePosition
                //
                lineNumber = _reader.LineNumber;
                linePosition = _reader.LinePosition + 3;

                utilWriter.Write("<?xml");

                //
                // Note that there is no way to get spacing between attribute name and value
                // For example:
                //
                //          <?xml attr="value" ?>
                //
                // is reported with the same position as
                //
                //          <?xml attr = "value" ?>
                //
                // The first example has no spaces around '=', the second example does.
                //
                while (_reader.MoveToNextAttribute()) {
                    // get line position of the attribute declaration
                    //      <?xml    version="1.0"
                    //               ^
                    //               attrLinePosition
                    //
                    int attrLineNumber = _reader.LineNumber;
                    int attrLinePosition = _reader.LinePosition;

                    // Write the whitespace before the attribute
                    utilWriter.AppendRequiredWhiteSpace(lineNumber, linePosition, attrLineNumber, attrLinePosition);

                    // Write the attribute and value
                    int charactersWritten = utilWriter.Write(_reader.Name);
                    charactersWritten += utilWriter.Write('=');
                    charactersWritten += utilWriter.AppendAttributeValue(_reader);

                    // Update position. Note that the attribute value is escaped to always be on a single line.
                    lineNumber = attrLineNumber;
                    linePosition = attrLinePosition + charactersWritten;
                }

                // Position reader at beginning of node
                _reader.MoveToElement();
            }
            else if (nodeType == XmlNodeType.SignificantWhitespace) {
                utilWriter.Write(_reader.Value);
            }
            else if (nodeType == XmlNodeType.ProcessingInstruction) {
                //
                // Note that there is no way to get spacing between attribute name and value
                // For example:
                //
                //          <?pi "value" ?>
                //
                // is reported with the same position as
                //
                //          <?pi    "value" ?>
                //
                // The first example has one space between 'pi' and "value", the second has multiple spaces.
                //
                utilWriter.AppendProcessingInstruction(_reader.Name, _reader.Value);
            }
            else if (nodeType == XmlNodeType.EntityReference) {
                utilWriter.AppendEntityRef(_reader.Name);
            }
            else if (nodeType == XmlNodeType.CDATA) {
                utilWriter.AppendCData(_reader.Value);
            }
            else if (nodeType == XmlNodeType.DocumentType) {
                // 
                // XmlNodeType.DocumentType has the following format:
                //
                //      <!DOCTYPE rootElementName {(SYSTEM uriRef)|(PUBLIC id uriRef)} {[ dtdDecls ]} >
                //
                // The reader only gives us the position of 'rootElementName', so we must track what was
                // written before "<!DOCTYPE" in order to correctly determine the position of the
                // <!DOCTYPE tag
                //
                Debug.Assert(utilWriter.TrackPosition, "utilWriter.TrackPosition");
                int c = utilWriter.Write("<!DOCTYPE");

                // Write the space between <!DOCTYPE and the rootElementName
                utilWriter.AppendRequiredWhiteSpace(_lastLineNumber, _lastLinePosition + c, _reader.LineNumber, _reader.LinePosition);

                // Write the rootElementName
                utilWriter.Write(_reader.Name);

                // Get the dtd declarations, if any
                string dtdValue = null;
                if (_reader.HasValue) {
                    dtdValue = _reader.Value;
                }

                // get line position after the !DOCTYPE declaration:
                //      <!DOCTYPE  rootElement     SYSTEM rootElementDtdUri >
                //                            ^
                //                            linePosition
                lineNumber = _reader.LineNumber;
                linePosition = _reader.LinePosition + _reader.Name.Length;

                // Note that there is no way to get the spacing after PUBLIC or SYSTEM attributes and their values
                if (_reader.MoveToFirstAttribute()) {
                    // Write the space before SYSTEM or PUBLIC
                    utilWriter.AppendRequiredWhiteSpace(lineNumber, linePosition, _reader.LineNumber, _reader.LinePosition); 

                    // Write SYSTEM or PUBLIC and the 1st value of the attribute
                    string attrName = _reader.Name;
                    utilWriter.Write(attrName);
                    utilWriter.AppendSpace();
                    utilWriter.AppendAttributeValue(_reader);
                    _reader.MoveToAttribute(0);
                    
                    // If PUBLIC, write the second value of the attribute
                    if (attrName == "PUBLIC") {
                        _reader.MoveToAttribute(1);
                        utilWriter.AppendSpace();
                        utilWriter.AppendAttributeValue(_reader);
                        _reader.MoveToAttribute(1);
                    }
                }

                // If there is a dtd, write it
                if (dtdValue != null && dtdValue.Length > 0) {
                    utilWriter.Write(" [");
                    utilWriter.Write(dtdValue);
                    utilWriter.Write(']');
                }

                utilWriter.Write('>');
            }

            // Advance the _reader so we can get the position of the next node.
            bool moreToRead = _reader.Read();
            nodeType = _reader.NodeType;

            // Close the node we are copying.
            if (close != null) {
                //
                // Find the position of the close string, for example:
                //
                //          <element      >  <subElement />
                //                        ^
                //                        closeLinePosition
                //
                int startOffset = GetPositionOffset(nodeType);
                int closeLineNumber = _reader.LineNumber;
                int closeLinePosition = _reader.LinePosition - startOffset - close.Length;

                // Add whitespace up to the position of the close string
                utilWriter.AppendWhiteSpace(lineNumber, linePosition, closeLineNumber, closeLinePosition);

                // Write the close string
                utilWriter.Write(close);
            }

            //
            // Track the position of the reader based on the position of the reader
            // before we copied this node and what we have written in copying the node.
            // This allows us to determine the position of the <!DOCTYPE tag.
            //
            if (utilWriter.TrackPosition) {
                _lastLineNumber = (readerLineNumber - writerLineNumber) + utilWriter.LineNumber;

                if (writerLineNumber == utilWriter.LineNumber) {
                    _lastLinePosition = (readerLinePosition - writerLinePosition) + utilWriter.LinePosition;
                }
                else {
                    _lastLinePosition = utilWriter.LinePosition;
                }
            }

            return moreToRead;
        }

Usage Example

        private void CopyConfigSource(XmlUtilWriter utilWriter, string updatedXml, string configSourceStreamName, byte[] buffer) {
            // only copy the byte order mark if it exists in the current web.config
            byte[] preamble;
            using (Stream stream = new MemoryStream(buffer)) {
                using (XmlUtil xmlUtil = new XmlUtil(stream, configSourceStreamName, true)) {
                    preamble = ConfigStreamInfo.StreamEncoding.GetPreamble();
                }
            }

            CheckPreamble(preamble, utilWriter, buffer);

            using (Stream stream = new MemoryStream(buffer)) {
                using (XmlUtil xmlUtil = new XmlUtil(stream, configSourceStreamName, false)) {
                    XmlTextReader reader = xmlUtil.Reader;

                    // copy up to the first element
                    reader.WhitespaceHandling = WhitespaceHandling.All;
                    reader.Read();

                    // determine the indent to use for the element
                    int indent = DEFAULT_INDENT;
                    int linePosition = 1;
                    bool hasElement = xmlUtil.CopyReaderToNextElement(utilWriter, false);
                    if (hasElement) {
                        // find the indent of the first attribute, if any
                        int lineNumber = reader.LineNumber;
                        linePosition = reader.LinePosition - 1;
                        int attributeIndent = 0;
                        while (reader.MoveToNextAttribute()) {
                            if (reader.LineNumber > lineNumber) {
                                attributeIndent =   reader.LinePosition - linePosition;
                                break;
                            }
                        }

                        // find the indent of the first sub element, if any
                        int elementIndent = 0;
                        reader.Read();
                        while (reader.Depth >= 1) {
                            if (reader.NodeType == XmlNodeType.Element) {
                                elementIndent = (reader.LinePosition - 1) - linePosition;
                                break;
                            }

                            reader.Read();
                        }

                        if (elementIndent > 0) {
                            indent = elementIndent;
                        }
                        else if (attributeIndent > 0) {
                            indent = attributeIndent;
                        }
                    }

                    // Write the config source
                    string formattedXml = XmlUtil.FormatXmlElement(updatedXml, linePosition, indent, true);
                    utilWriter.Write(formattedXml);

                    // Copy remaining contents
                    if (hasElement) {
                        // Skip over the existing element
                        while (reader.Depth > 0) {
                            reader.Read();
                        }

                        if (reader.IsEmptyElement || reader.NodeType == XmlNodeType.EndElement) {
                            reader.Read();
                        }

                        // Copy remainder of file
                        while (xmlUtil.CopyXmlNode(utilWriter)) {
                        }
                    }
                }
            }
        }
All Usage Examples Of System.Configuration.XmlUtil::CopyXmlNode