xml_parser_util.dart 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // ignore_for_file: implementation_imports
  2. import "package:xml/src/xml/entities/named_entities.dart";
  3. import "package:xml/xml.dart";
  4. // for converting the response to xml
  5. String convertJs2Xml(Map<String, dynamic> json) {
  6. final builder = XmlBuilder();
  7. buildXml(builder, json);
  8. return builder.buildDocument().toXmlString(
  9. pretty: true,
  10. indent: ' ',
  11. entityMapping: defaultMyEntityMapping,
  12. );
  13. }
  14. void buildXml(XmlBuilder builder, dynamic node) {
  15. if (node is Map<String, dynamic>) {
  16. node.forEach((key, value) {
  17. builder.element(key, nest: () => buildXml(builder, value));
  18. });
  19. } else if (node is List<dynamic>) {
  20. for (var item in node) {
  21. buildXml(builder, item);
  22. }
  23. } else {
  24. builder.element(
  25. "Part",
  26. nest: () {
  27. builder.attribute(
  28. "PartNumber",
  29. (node as MapEntry<int, String>).key + 1,
  30. );
  31. builder.attribute("ETag", node.value);
  32. },
  33. );
  34. }
  35. }
  36. XmlEntityMapping defaultMyEntityMapping = MyXmlDefaultEntityMapping.xml();
  37. class MyXmlDefaultEntityMapping extends XmlDefaultEntityMapping {
  38. MyXmlDefaultEntityMapping.xml() : this(xmlEntities);
  39. MyXmlDefaultEntityMapping.html() : this(htmlEntities);
  40. MyXmlDefaultEntityMapping.html5() : this(html5Entities);
  41. MyXmlDefaultEntityMapping(super.entities);
  42. @override
  43. String encodeText(String input) =>
  44. input.replaceAllMapped(_textPattern, _textReplace);
  45. @override
  46. String encodeAttributeValue(String input, XmlAttributeType type) {
  47. switch (type) {
  48. case XmlAttributeType.SINGLE_QUOTE:
  49. return input.replaceAllMapped(
  50. _singeQuoteAttributePattern,
  51. _singeQuoteAttributeReplace,
  52. );
  53. case XmlAttributeType.DOUBLE_QUOTE:
  54. return input.replaceAllMapped(
  55. _doubleQuoteAttributePattern,
  56. _doubleQuoteAttributeReplace,
  57. );
  58. }
  59. }
  60. }
  61. final _textPattern = RegExp(r'[&<>' + _highlyDiscouragedCharClass + r']');
  62. String _textReplace(Match match) {
  63. final toEscape = match.group(0)!;
  64. switch (toEscape) {
  65. case '<':
  66. return '&lt;';
  67. case '&':
  68. return '&amp;';
  69. case '>':
  70. return '&gt;';
  71. default:
  72. return _asNumericCharacterReferences(toEscape);
  73. }
  74. }
  75. final _singeQuoteAttributePattern =
  76. RegExp(r"['&<>\n\r\t" + _highlyDiscouragedCharClass + r']');
  77. String _singeQuoteAttributeReplace(Match match) {
  78. final toEscape = match.group(0)!;
  79. switch (toEscape) {
  80. case "'":
  81. return '';
  82. case '&':
  83. return '&amp;';
  84. case '<':
  85. return '&lt;';
  86. case '>':
  87. return '&gt;';
  88. default:
  89. return _asNumericCharacterReferences(toEscape);
  90. }
  91. }
  92. final _doubleQuoteAttributePattern =
  93. RegExp(r'["&<>\n\r\t' + _highlyDiscouragedCharClass + r']');
  94. String _doubleQuoteAttributeReplace(Match match) {
  95. final toEscape = match.group(0)!;
  96. switch (toEscape) {
  97. case '"':
  98. return '';
  99. case '&':
  100. return '&amp;';
  101. case '<':
  102. return '&lt;';
  103. case '>':
  104. return '&gt;';
  105. default:
  106. return _asNumericCharacterReferences(toEscape);
  107. }
  108. }
  109. const _highlyDiscouragedCharClass =
  110. r'\u0001-\u0008\u000b\u000c\u000e-\u001f\u007f-\u0084\u0086-\u009f';
  111. String _asNumericCharacterReferences(String toEscape) => toEscape.runes
  112. .map((rune) => '&#x${rune.toRadixString(16).toUpperCase()};')
  113. .join();