shamblett / xml2json

XML to JSON conversion for Dart
MIT License
54 stars 19 forks source link

Transform wrong result of list type #33

Closed lzmy1993 closed 3 years ago

lzmy1993 commented 3 years ago

from:<root><item>1</item><item>2</item><item>three</item></root> usage:xml2json.toParker() result:{"root": {"item": "three"}}

not:{"item": ["1","2","three"]}

shamblett commented 3 years ago

OK I'll look at this.

JuneCheng commented 3 years ago

from:<root><item>1</item><item>2</item><item>three</item></root> usage:xml2json.toParker() result:{"root": {"item": "three"}}

not:{"item": ["1","2","three"]}

用以下代码替换掉xml2json_parker.dart文件中的所有代码即可,顺便支持了解析节点中的attrs属性。

/*
 * Package : xml2json
 * Author : S. Hamblett <steve.hamblett@linux.com>
 * Date   : 12/09/2013
 * Copyright :  S.Hamblett@OSCF
 */

part of xml2json;

/// Parker transform class
class _Xml2JsonParker {
  /// Parker transformer function.
  Map<dynamic, dynamic>? _transform(dynamic node, dynamic objin) {
    Map<dynamic, dynamic>? obj = objin;
    if (node is XmlElement) {
      final nodeName = '"${node.name.qualified}"';
      // print('nodeName----------->$nodeName');
      if (obj![nodeName] is List && !obj.keys.contains(nodeName)) {
        obj[nodeName].add(<dynamic, dynamic>{});
        obj = obj[nodeName].last;
      } else if (obj[nodeName] is Map && !obj.keys.contains(nodeName)) {
        obj[nodeName] = <dynamic>[obj[nodeName], <dynamic, dynamic>{}];
        obj = obj[nodeName].last;
      } else {
        if (node.children.isNotEmpty) {
          if (node.children[0] is XmlText) {
            _parseXmlTextNode(node, obj, nodeName);
          } else if (node.children[0] is XmlCDATA) {
            final sanitisedNodeData = _Xml2JsonUtils.escapeTextForJson(node.children[0].text);
            var nodeData = '"$sanitisedNodeData"';
            if (nodeData.isEmpty) {
              nodeData = '';
            }
            obj[nodeName] = nodeData;
          } else if (obj[nodeName] is Map) {
            var jsonCopy = json.decode(json.encode(obj[nodeName]));
            obj[nodeName] = <dynamic>[jsonCopy, <dynamic, dynamic>{}];
            obj = obj[nodeName].last;
          } else if (obj[nodeName] is List) {
            obj[nodeName].add(<dynamic, dynamic>{});
            obj = obj[nodeName].last;
          } else {
            obj[nodeName] = <dynamic, dynamic>{};
            obj = obj[nodeName];
          }
          if (node.attributes.isNotEmpty) {
            _parseAttrs(node, obj);
          }
        } else {
          /* No children, empty element */
          obj[nodeName] = null;
        }
      }

      for (var j = 0; j < node.children.length; j++) {
        _transform(node.children[j], obj);
      }
    } else if (node is XmlDocument) {
      for (var j = 0; j < node.children.length; j++) {
        _transform(node.children[j], obj);
      }
    }

    return obj;
  }

  /// 解析节点里的属性值
  void _parseAttrs(dynamic node, dynamic obj) {
    node.attributes.forEach((attr) {
      obj!['"_${attr.name.local}"'] = '"${attr.value}"';
    });
  }

  /// 解析XmlText节点
  void _parseXmlTextNode(dynamic node, dynamic obj, dynamic nodeName) {
    final sanitisedNodeData = _Xml2JsonUtils.escapeTextForJson(node.children[0].text);
    var nodeData = '"$sanitisedNodeData"';
    // print('nodeData----------->$nodeData');
    if (nodeData.isEmpty) {
      nodeData = '';
    }
    var attrs = node.attributes;
    // 如果开始节点里有属性
    if (attrs.isNotEmpty) {
      var objTemp = <dynamic, dynamic>{};
      _parseAttrs(node, objTemp);
      objTemp['"value"'] = nodeData;
      if (obj[nodeName] is Map) {
        var jsonCopy = json.decode(json.encode(obj[nodeName]));
        obj[nodeName] = <dynamic>[jsonCopy, objTemp];
      } else if (obj[nodeName] is List) {
        obj[nodeName].add(objTemp);
      } else {
        obj[nodeName] = objTemp;
      }
    } else {
      if (obj[nodeName] is String) {
        obj[nodeName] = <dynamic>[obj[nodeName], nodeData];
      } else if (obj[nodeName] is List) {
        obj[nodeName].add(nodeData);
      } else {
        obj[nodeName] = nodeData;
      }
    }
  }

  /// Transformer function
  String transform(XmlDocument? xmlNode) {
    Map<dynamic, dynamic>? json;
    try {
      json = _transform(xmlNode, <dynamic, dynamic>{});
    } on Exception catch (e) {
      throw Xml2JsonException('Parker internal transform error => ${e.toString()}');
    }

    return json.toString();
  }
}
shamblett commented 3 years ago

The above code breaks this existing unit test 'Transform Complex test string' in the 'Parker' group of the xml2json_test.dart unit test file -

Expected: '{"reports":"Thisiscdatawith\\"quotes\\"","entry":[{"id":"tag:open311.sfgov.org,2010-04-15:/dev/V1/reports/637619.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637619","address":"1600MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hours&/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2011-04-15:/dev/V1/reports/637620.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637620","address":"56MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2012-04-15:/dev/V1/reports/637621.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637621","address":"1800MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}}]}'
  Actual: '{"reports":"Thisiscdatawith\\"quotes\\"","entry":{"id":"tag:open311.sfgov.org,2012-04-15:/dev/V1/reports/637621.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":{"_label":"Damagedtree","_term":"tree-damage","_scheme":"https://open311.sfgov.org/dev/V1/categories/006.xml","value":"006"},"content":{"report_id":"637621","address":"1800MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}}}'
   Which: is different.
          Expected: ... ","entry":[{"id":"ta ...
            Actual: ... ","entry":{"id":"tag ...
                                  ^
           Differ at offset 49

Also the actual output generated is -

'{"root": {"item": ["1", "2", "three"]}}'

is this what you expect?

lzmy1993 commented 3 years ago

The above code breaks this existing unit test 'Transform Complex test string' in the 'Parker' group of the xml2json_test.dart unit test file -

Expected: '{"reports":"Thisiscdatawith\\"quotes\\"","entry":[{"id":"tag:open311.sfgov.org,2010-04-15:/dev/V1/reports/637619.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637619","address":"1600MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hours&/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2011-04-15:/dev/V1/reports/637620.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637620","address":"56MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2012-04-15:/dev/V1/reports/637621.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637621","address":"1800MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}}]}'
  Actual: '{"reports":"Thisiscdatawith\\"quotes\\"","entry":{"id":"tag:open311.sfgov.org,2012-04-15:/dev/V1/reports/637621.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":{"_label":"Damagedtree","_term":"tree-damage","_scheme":"https://open311.sfgov.org/dev/V1/categories/006.xml","value":"006"},"content":{"report_id":"637621","address":"1800MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}}}'
   Which: is different.
          Expected: ... ","entry":[{"id":"ta ...
            Actual: ... ","entry":{"id":"tag ...
                                  ^
           Differ at offset 49

Also the actual output generated is -

'{"root": {"item": ["1", "2", "three"]}}'

is this what you expect?

Yes,the data is a list in XML,so I want a list rather than the last element of list in json after transform!!!

JuneCheng commented 3 years ago

The above code breaks this existing unit test 'Transform Complex test string' in the 'Parker' group of the xml2json_test.dart unit test file -

Expected: '{"reports":"Thisiscdatawith\\"quotes\\"","entry":[{"id":"tag:open311.sfgov.org,2010-04-15:/dev/V1/reports/637619.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637619","address":"1600MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hours&/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2011-04-15:/dev/V1/reports/637620.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637620","address":"56MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2012-04-15:/dev/V1/reports/637621.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637621","address":"1800MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}}]}'
  Actual: '{"reports":"Thisiscdatawith\\"quotes\\"","entry":{"id":"tag:open311.sfgov.org,2012-04-15:/dev/V1/reports/637621.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":{"_label":"Damagedtree","_term":"tree-damage","_scheme":"https://open311.sfgov.org/dev/V1/categories/006.xml","value":"006"},"content":{"report_id":"637621","address":"1800MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}}}'
   Which: is different.
          Expected: ... ","entry":[{"id":"ta ...
            Actual: ... ","entry":{"id":"tag ...
                                  ^
           Differ at offset 49

Also the actual output generated is -

'{"root": {"item": ["1", "2", "three"]}}'

is this what you expect?

I have fixed the problem you said. Please try the codes above again. However, due to the addition of attribute parsing, the data structure generated by parsing will be a little different, which will affect the users who rely on this plug-in before. So you need to remove the attribute parsing method.

shamblett commented 3 years ago

The updated code you have provided now breaks 2 unit tests -

Testing started at 10:55 ...

Expected: '{"contacts":{"contact":{"name":"JohnDoe","phone":"123-\\"456\\"-7890","address":{"street":"123JFKStreet","city":"AnyTown","state":"AnyState","zipCode":"12345"}}}}'
  Actual: '{"contacts":{"contact":{"_id":"1","name":"JohnDoe","phone":"123-\\"456\\"-7890","address":{"street":"123JFKStreet","city":"AnyTown","state":"AnyState","zipCode":"12345"}}}}'
   Which: is different.
          Expected: ... ontact":{"name":"Joh ...
            Actual: ... ontact":{"_id":"1"," ...
                                  ^
           Differ at offset 25

package:test_api               expect
test/xml2json_test.dart 136:7  main.<fn>.<fn>

Expected: '{"reports":"Thisiscdatawith\\"quotes\\"","entry":[{"id":"tag:open311.sfgov.org,2010-04-15:/dev/V1/reports/637619.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637619","address":"1600MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hours&/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2011-04-15:/dev/V1/reports/637620.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637620","address":"56MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2012-04-15:/dev/V1/reports/637621.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":"006","content":{"report_id":"637621","address":"1800MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}}]}'
  Actual: '{"reports":"Thisiscdatawith\\"quotes\\"","_xmlns":"http://www.w3.org/2005/Atom","_georss":"http://www.georss.org/georss","entry":[{"id":"tag:open311.sfgov.org,2010-04-15:/dev/V1/reports/637619.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":{"_label":"Damagedtree","_term":"tree-damage","_scheme":"https://open311.sfgov.org/dev/V1/categories/006.xml","value":"006"},"_label":"Damagedtree","_term":"tree-damage","_scheme":"https://open311.sfgov.org/dev/V1/categories/006.xml","content":{"_type":"xml","_xmlns":"http://open311.org/spec/georeport-v1","report_id":"637619","address":"1600MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hours&/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2011-04-15:/dev/V1/reports/637620.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":{"_label":"Damagedtree","_term":"tree-damage","_scheme":"https://open311.sfgov.org/dev/V1/categories/006.xml","value":"006"},"_label":"Damagedtree","_term":"tree-damage","_scheme":"https://open311.sfgov.org/dev/V1/categories/006.xml","content":{"_type":"xml","_xmlns":"http://open311.org/spec/georeport-v1","report_id":"637620","address":"56MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}},{"id":"tag:open311.sfgov.org,2012-04-15:/dev/V1/reports/637621.xml","title":"Alargetreebranchisblockingtheroad","updated":"2010-04-13T18:30:02-05:00","link":null,"author":{"name":"JohnDoe"},"georss:point":"40.7111-73.9565","category":{"_label":"Damagedtree","_term":"tree-damage","_scheme":"https://open311.sfgov.org/dev/V1/categories/006.xml","value":"006"},"_label":"Damagedtree","_term":"tree-damage","_scheme":"https://open311.sfgov.org/dev/V1/categories/006.xml","content":{"_type":"xml","_xmlns":"http://open311.org/spec/georeport-v1","report_id":"637621","address":"1800MarketSt,SanFrancisco,CA94103","description":"Alargetreebranchisblockingtheroad","status":"created","status_notes":null,"policy":"TheCitywillinspectandrequiretheresponsiblepartytocorrectwithin24hoursand/orissueaCorrectionNoticeorNoticeofViolationofthePublicWorksCode"}}]}'
   Which: is different.
          Expected: ... otes\\"","entry":[{" ...
            Actual: ... otes\\"","_xmlns":"h ...
                                  ^
           Differ at offset 42

package:test_api               expect
test/xml2json_test.dart 151:7  main.<fn>.<fn>

Process finished with exit code 1

I don't know what you mean by 'So you need to remove the attribute parsing method.'

Update your code so that it passes all existing unit tests and submit it as a pull request in the normal manner, then I can see whats going on better.

shamblett commented 3 years ago

Pull request integrated into the package and re published at version 5.2.0. Please update and re test.