/// <summary> /// Creates the tokens that describe an element from a <see cref="XmlReader"/> is positioned on an element /// node. /// </summary> /// <param name="reader"> /// The reader. /// </param> /// <returns> /// The newly created <see cref="FragmentToken"/>. /// </returns> private IEnumerable <FragmentToken> CreateElementTokens(XmlReader reader) { var elementName = reader.Name; var tokenDetails = new ElementTokenDetails(reader.XmlSpace, reader.IsEmptyElement); yield return(new FragmentToken(FragmentType.Element, elementName, tokenDetails)); var attributeTokens = new List <FragmentToken>(); while (reader.MoveToNextAttribute()) { ++tokenDetails.AttributeCount; attributeTokens.Add(XmlTokenizer.CreateAttributeToken(reader)); } var comparer = this.attributeOrderOverride.Any() ? new AttributeNameComparer(this.attributeOrderOverride) : XmlTokenizer.AttributeNameComparer; foreach (var token in attributeTokens.OrderBy(item => item.Name, comparer)) { yield return(token); } this.attributeOrderOverride.Clear(); yield return(new FragmentToken(FragmentType.CloseElement, elementName, tokenDetails)); if (tokenDetails.IsEmptyElement) { yield return(new FragmentToken(FragmentType.EndElement, elementName, string.Empty)); } }
/// <summary> /// Tokenizes the XML in a <see cref="XmlReader"/> to a sequence of <see cref="FragmentToken"/>. /// </summary> /// <param name="reader"> /// The reader. /// </param> /// <returns> /// A sequence of <see cref="FragmentToken"/> representing the XML. /// </returns> /// <exception cref="InvalidOperationException"> /// An unknown node type is encountered. /// </exception> public IEnumerable <FragmentToken> Tokenize(XmlReader reader) { var result = new List <FragmentToken>(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Comment: result.Add(this.CreateCommentToken(reader)); break; case XmlNodeType.Whitespace: case XmlNodeType.SignificantWhitespace: case XmlNodeType.Text: case XmlNodeType.EndElement: case XmlNodeType.ProcessingInstruction: case XmlNodeType.XmlDeclaration: result.Add(XmlTokenizer.CreateToken(reader)); break; case XmlNodeType.Element: result.AddRange(this.CreateElementTokens(reader)); break; default: throw new InvalidOperationException($"Unknown XmlNodeType '{reader.NodeType}'"); } } return(result); }
/// <summary> /// Creates a token that describe an attribute from a <see cref="XmlReader"/> is positioned on an attribute /// node. /// </summary> /// <param name="reader"> /// The reader. /// </param> /// <returns> /// The newly created <see cref="FragmentToken"/>. /// </returns> private static FragmentToken CreateAttributeToken(XmlReader reader) { IMarkupExtensionInfo markup; if (XmlTokenizer.MarkupExtensionParser.TryParse(reader.Value, out markup)) { return(new FragmentToken(FragmentType.Attribute, reader.Name, markup)); } return(XmlTokenizer.CreateToken(reader)); }
/// <summary> /// Formats a XAML document. /// </summary> /// <param name="obj"> /// A string containing the XAML document to format. /// </param> /// <param name="builder"> /// The string builder to which the formatter outputs. /// </param> public void Format(object obj, StringBuilder builder) { if (obj == null) { throw new ArgumentNullException(nameof(obj)); } if (builder == null) { throw new ArgumentNullException(nameof(builder)); } var xaml = obj as string; if (xaml == null) { throw new ArgumentException(@"Parameter must be of type string", nameof(obj)); } using (var stringReader = new StringReader(xaml)) { try { using (var xmlReader = XmlReader.Create(stringReader, new XmlReaderSettings { CloseInput = false })) { var tokens = new XmlTokenizer() .Tokenize(xmlReader) .SkipWhile(candidate => candidate.Type == FragmentType.WhiteSpace); this.context.TokenSource = new FragmentTokenSource(tokens); var ignore = this.context.TokenSource .LookAhead .TakeWhile(item => item.Type == FragmentType.Comment || item.Type == FragmentType.WhiteSpace) .Any(item => XamlFormatter.Ignore.IsMatch(item.ContentString)); if (ignore) { throw new WarningException("Document has been ignored"); } while (this.context.TokenSource.MoveNext()) { this.context .Create(this.context.TokenSource.Token.Type) .Format(this.context.TokenSource.Token, builder); } } } catch (Exception ex) { Debug.WriteLine("Failed to format the document: {0}{1}", ex.Message, null); throw; } } builder.RemoveEndWhile(char.IsWhiteSpace); }