/// <summary> /// Converts an existing XML document into the equivlent new YAML format. /// </summary> /// <param name="xml">The existing <see cref="XDocument"/>.</param> /// <returns>The corresponding YAML and the list of unknown attributes.</returns> internal (string Yaml, List <string> UnknownAttributes) ConvertXmlToYaml(XDocument xml) { if (xml == null) { throw new ArgumentNullException(nameof(xml)); } if (xml.Root.Name.LocalName != "CodeGeneration") { throw new ArgumentException("Root element must be named 'CodeGeneration'.", nameof(xml)); } var sb = new StringBuilder(); List <string> unknownAttributes; using (var sw = new StringWriter(sb)) { var(entity, type, _) = GetEntityConfigInfo(xml.Root.Name.LocalName); var yfa = new YamlFormatArgs(sw); WriteElement(yfa, xml.Root, ConfigType, entity, type); unknownAttributes = yfa.UnknownAttributes; } return(sb.ToString(), unknownAttributes); }
/// <summary> /// Writes the XML comments as YAML. /// </summary> private static void WriteComments(YamlFormatArgs args, XElement xml) { if (xml.PreviousNode != null && xml.PreviousNode.NodeType == System.Xml.XmlNodeType.Comment) { using var sr = new StringReader(((XComment)xml.PreviousNode).Value); while (true) { var line = sr.ReadLine(); if (line == null) { break; } else { args.Writer.WriteLine($"{new string(' ', args.Indent + 2)}# {line.Trim()}"); } } } }
/// <summary> /// Writes the XML attribues as YAML. /// </summary> private static void WriteAttributes(YamlFormatArgs args, ConfigType ct, ConfigurationEntity ce, Type type, XElement xml) { var needsComma = false; foreach (var att in xml.Attributes()) { var jname = XmlYamlTranslate.GetYamlName(ct, ce, att.Name.LocalName); var pi = type.GetProperty(StringConversion.ToPascalCase(jname) !); var val = XmlYamlTranslate.GetYamlValue(ct, ce, att.Name.LocalName, att.Value); if (val == null) { continue; } if (pi == null || pi.GetCustomAttribute <JsonPropertyAttribute>() == null) { jname = att.Name.LocalName; args.UnknownAttributes.Add($"{xml.Name.LocalName}.{jname} = {val}"); } if (needsComma) { args.Writer.Write(", "); } args.HasAttributes = true; args.Writer.Write($"{jname}: {val}"); if (args.Indent > 0) { needsComma = true; } else { args.Writer.WriteLine(); } } }
/// <summary> /// Writes the XML element as YAML. /// </summary> private void WriteElement(YamlFormatArgs args, XElement xml, ConfigType ct, ConfigurationEntity entity, Type type) { WriteComments(args, xml); args.Indent += 2; if (args.Indent == 2) { args.Writer.Write("- { "); } else if (args.Indent > 0) { args.Writer.Write($"{new string(' ', args.Indent)}{{ "); } WriteAttributes(args, ct, entity, type, xml); // Group by element name, then process as a collection. int i = 0; var coll = xml.Elements().GroupBy(x => x.Name).Select(g => new { g.Key, Children = xml.Elements(g.Key) }); foreach (var grp in coll) { var info = GetEntityConfigInfo(grp.Key.LocalName); if (info.entity == ConfigurationEntity.None) { return; } if (args.Indent > 0) { args.Writer.WriteLine(","); args.Indent += 2; args.Writer.Write($"{new string(' ', args.Indent)}{info.name}:"); } else { args.Writer.Write($"{info.name}:"); } if (args.Indent > 0) { args.Writer.Write(" ["); } args.Writer.WriteLine(); int j = 0; foreach (var child in grp.Children) { if (j++ > 0) { args.WriteClosingSquigglyBracket(); if (args.Indent > 0) { args.Writer.Write(","); } args.Writer.WriteLine(); } if (args.Indent == 0 && !child.Equals(xml.Document.Root.Elements().First())) { args.Writer.WriteLine(); } args.Level++; WriteElement(args, child, ct, info.entity, info.type); args.Level--; } args.WriteClosingSquigglyBracket(); args.Writer.WriteLine(); if (args.Indent > 0) { args.Writer.Write($"{new string(' ', args.Indent)}]"); args.Indent -= 2; } i++; if (i == coll.Count()) { args.Writer.WriteLine(); if (args.Indent > 0) { args.Writer.Write($"{new string(' ', args.Indent)}"); } } } args.Indent -= 2; }