private void InsertNewlineToUnderlyingStream(PauseableWriteableStream writerStream, [NotNull] XmlStreamFormatterContext context) { writerStream.WriteByte(13); writerStream.WriteByte(10); for (var i = 0; i < context.CurrentElementDepth; i++) { writerStream.Write(context.IndentByteSequence, 0, context.IndentByteSequence.Length); } }
private bool OnCopyCallback( XmlNodeType nodeType, XmlReader xmlReader, XmlWriter xmlWriter, PauseableWriteableStream writerStream, [NotNull] XmlStreamFormatterOptions options, [NotNull] XmlStreamFormatterContext context) { if (!options.WrapLongElementLines) { return(true); } if (nodeType == XmlNodeType.Element) { context.CurrentLineLength = xmlReader.Prefix.Length // prefix - if any + (string.IsNullOrEmpty(xmlReader.Prefix) ? 0 : 1) // colon between prefix and local name, if any + xmlReader.LocalName.Length // local name + 1; // opening triangular brace context.CurrentElementDepth++; return(true); } if (nodeType == XmlNodeType.EndElement) { context.CurrentAttributeCountOnElement = 0; context.CurrentLineLength = null; context.CurrentElementDepth--; return(true); } if (nodeType == XmlNodeType.Attribute) { context.CurrentAttributeCountOnElement++; Debug.Assert(context.CurrentLineLength.HasValue, "_currentLineLength cannot be null at attribute"); // we want the underlying writer to think the attributes have been written, even though we will write them out "raw" // to the underlying stream, so we will "pause" the underlying stream, writer the xmlns attribute, and resume. The writer thinks // the attribute has been written, but it doesn't appear in the output! // This is especially important of xmlns attributes as if we don't write these out, the writer won't think they've has been written // and will start appending namespace declarations to child nodes explicitly as it encounters nodes that use them. xmlWriter.Flush(); writerStream.PauseWriting(); xmlWriter.WriteAttributeString(xmlReader.Prefix, xmlReader.LocalName, xmlReader.NamespaceURI, xmlReader.Value); xmlWriter.Flush(); writerStream.ResumeWriting(); xmlWriter.Flush(); var sb = new StringBuilder(); if (!string.IsNullOrEmpty(xmlReader.Prefix)) { sb.Append(xmlReader.Prefix); sb.Append(":"); } sb.AppendFormat(@"{0}=""{1}""", xmlReader.LocalName, SecurityElement.Escape(xmlReader.Value)); if (context.CurrentLineLength + sb.Length + 1 > options.MaxElementLineLength) { InsertNewlineToUnderlyingStream(writerStream, context); var attributeAsBytes = context.Encoding.GetBytes(sb.ToString()); writerStream.Write(attributeAsBytes, 0, attributeAsBytes.Length); context.CurrentLineLength = sb.Length; if (sb.Length > options.MaxElementLineLength && context.CurrentAttributeCountOnElement < xmlReader.AttributeCount) { // this single attribute itself was bigger than the line length, and there are more attributes remaining. // Insert another newline. InsertNewlineToUnderlyingStream(writerStream, context); context.CurrentLineLength = 0; } return(false); } else { if (context.CurrentLineLength != 0) { sb.Insert(0, " "); } var attributeAsBytes = context.Encoding.GetBytes(sb.ToString()); writerStream.Write(attributeAsBytes, 0, attributeAsBytes.Length); context.CurrentLineLength += sb.Length; return(false); } } return(true); }