/AvalonEdit/ICSharpCode.AvalonEdit/Xml/CanonicalPrintAXmlVisitor.cs

http://github.com/icsharpcode/ILSpy · C# · 119 lines · 92 code · 10 blank · 17 comment · 18 complexity · 91d939e5cfce2eda435eb620f563d48a MD5 · raw file

  1. // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
  2. // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
  3. using System;
  4. using System.Linq;
  5. using System.Text;
  6. namespace ICSharpCode.AvalonEdit.Xml
  7. {
  8. /// <summary>
  9. /// Converts the XML tree back to text in canonical form.
  10. /// See http://www.w3.org/TR/xml-c14n
  11. /// </summary>
  12. public class CanonicalPrintAXmlVisitor: AbstractAXmlVisitor
  13. {
  14. StringBuilder sb = new StringBuilder();
  15. /// <summary>
  16. /// Gets the pretty printed text
  17. /// </summary>
  18. public string Output {
  19. get {
  20. return sb.ToString();
  21. }
  22. }
  23. /// <summary> Create canonical text from a document </summary>
  24. public static string Print(AXmlDocument doc)
  25. {
  26. CanonicalPrintAXmlVisitor visitor = new CanonicalPrintAXmlVisitor();
  27. visitor.VisitDocument(doc);
  28. return visitor.Output;
  29. }
  30. /// <summary> Visit RawDocument </summary>
  31. public override void VisitDocument(AXmlDocument document)
  32. {
  33. foreach(AXmlObject child in document.Children) {
  34. AXmlTag childAsTag = child as AXmlTag;
  35. // Only procssing instructions or elements
  36. if (childAsTag != null && childAsTag.IsProcessingInstruction && childAsTag.Name != "xml") {
  37. VisitTag(childAsTag);
  38. } else {
  39. AXmlElement childAsElement = child as AXmlElement;
  40. if (childAsElement != null) {
  41. VisitElement(childAsElement);
  42. }
  43. }
  44. }
  45. }
  46. /// <summary> Visit RawElement </summary>
  47. public override void VisitElement(AXmlElement element)
  48. {
  49. base.VisitElement(element);
  50. }
  51. /// <summary> Visit RawTag </summary>
  52. public override void VisitTag(AXmlTag tag)
  53. {
  54. if (tag.IsStartOrEmptyTag) {
  55. sb.Append('<');
  56. sb.Append(tag.Name);
  57. foreach(AXmlAttribute attr in tag.Children.OfType<AXmlAttribute>().OrderBy(a => a.Name)) {
  58. VisitAttribute(attr);
  59. }
  60. sb.Append('>');
  61. if (tag.IsEmptyTag) {
  62. // Use explicit start-end pair
  63. sb.AppendFormat("</{0}>", tag.Name);
  64. }
  65. } else if (tag.IsEndTag) {
  66. sb.AppendFormat("</{0}>", tag.Name);
  67. } else if (tag.IsProcessingInstruction) {
  68. sb.Append("<?");
  69. sb.Append(tag.Name);
  70. foreach(AXmlText text in tag.Children.OfType<AXmlText>()) {
  71. sb.Append(text.Value);
  72. }
  73. if (tag.Children.Count == 0)
  74. sb.Append(' ');
  75. sb.Append("?>");
  76. } else if (tag.IsCData) {
  77. foreach(AXmlText text in tag.Children.OfType<AXmlText>()) {
  78. sb.Append(Escape(text.Value));
  79. }
  80. }
  81. }
  82. /// <summary> Visit RawAttribute </summary>
  83. public override void VisitAttribute(AXmlAttribute attribute)
  84. {
  85. sb.Append(' ');
  86. sb.Append(attribute.Name);
  87. sb.Append("=");
  88. sb.Append('"');
  89. sb.Append(Escape(attribute.Value));
  90. sb.Append('"');
  91. }
  92. /// <summary> Visit RawText </summary>
  93. public override void VisitText(AXmlText text)
  94. {
  95. sb.Append(Escape(text.Value));
  96. }
  97. static string Escape(string text)
  98. {
  99. return text
  100. .Replace("&", "&amp;")
  101. .Replace("<", "&lt;")
  102. .Replace(">", "&gt;")
  103. .Replace("\"", "&quot;")
  104. .Replace("\u0009", "&#9;")
  105. .Replace("\u000A", "&#10;")
  106. .Replace("\u000D", "&#13;");
  107. }
  108. }
  109. }