From 2585691f6a3a1a1f01c90453b3d04cbf63647489 Mon Sep 17 00:00:00 2001 From: Karol Date: Thu, 12 Oct 2023 22:50:35 +0200 Subject: [PATCH 1/2] add order to json, since json does not guarantee the order of inserted keys, but it is important for xml --- lib/dachsfisch/json2_xml_converter.rb | 6 +- lib/dachsfisch/xml2_json_converter.rb | 9 +- spec/support/examples.rb | 208 +++++++++++++++++++------- 3 files changed, 161 insertions(+), 62 deletions(-) diff --git a/lib/dachsfisch/json2_xml_converter.rb b/lib/dachsfisch/json2_xml_converter.rb index 51b9139..45a61a1 100644 --- a/lib/dachsfisch/json2_xml_converter.rb +++ b/lib/dachsfisch/json2_xml_converter.rb @@ -23,8 +23,8 @@ def execute def add_element(xml, element) return unless element.is_a? Hash - element.each do |key, value| - add_node(xml, key, value) unless key.start_with?('@') + element['@@order']&.each do |key| + add_node(xml, key, element[key]) unless key.start_with?('@') end end @@ -44,7 +44,7 @@ def add_node(xml, key, element) end def handle_attribute_and_namespaces(node, element) - element.keys.filter {|element_key| element_key.start_with?('@') }.each do |attribute_key| + element.keys.filter {|element_key| element_key.start_with?(/@[^@]/) }.each do |attribute_key| if attribute_key.start_with? '@xmlns' element[attribute_key].each do |namespace_key, namespace| # add namespace of current scope to node. The root-ns($) gets 'xmlns' as key, named namespaces 'xmlns:name' respectively. diff --git a/lib/dachsfisch/xml2_json_converter.rb b/lib/dachsfisch/xml2_json_converter.rb index 490f2e1..d13438a 100644 --- a/lib/dachsfisch/xml2_json_converter.rb +++ b/lib/dachsfisch/xml2_json_converter.rb @@ -14,20 +14,27 @@ def execute @fragment.elements.deconstruct.each do |root| result[node_name(root)] = extract_node(root) end + add_order_to_hash result result.to_json end private + def add_order_to_hash(hash) + return if hash.keys.reject {|key| key.start_with?('@') }.empty? + + hash['@@order'] = hash.keys.reject {|key| key.start_with?('@') } + end + def extract_node(node) hash = {} active_namespaces = add_namespaces_to_active_namespaces(node) hash['@xmlns'] = active_namespaces unless active_namespaces.empty? - handle_attributes(hash, node) node.children.each do |child| handle_content(hash, child) end + add_order_to_hash hash hash end diff --git a/spec/support/examples.rb b/spec/support/examples.rb index 893389f..2072f0d 100644 --- a/spec/support/examples.rb +++ b/spec/support/examples.rb @@ -13,8 +13,10 @@ def self.json <<~JSON { "alice": { - "$1": "bob" - } + "$1": "bob", + "@@order": ["$1"] + }, + "@@order": ["alice"] } JSON end @@ -31,8 +33,10 @@ def self.json <<~JSON { "test": { - "$1": "test" - } + "$1": "test", + "@@order": ["$1"] + }, + "@@order": ["test"] } JSON end @@ -50,12 +54,16 @@ def self.json { "alice": { "bob": { - "$1": "charlie" + "$1": "charlie", + "@@order": ["$1"] }, "david": { - "$1": "edgar" - } - } + "$1": "edgar", + "@@order": ["$1"] + }, + "@@order": ["bob", "david"] + }, + "@@order": ["alice"] } JSON end @@ -77,13 +85,17 @@ def self.json "alice": { "bob": [ { - "$1": "charlie" + "$1": "charlie", + "@@order": ["$1"] }, { - "$1": "david" + "$1": "david", + "@@order": ["$1"] } - ] - } + ], + "@@order": ["bob"] + }, + "@@order": ["alice"] } JSON end @@ -104,8 +116,10 @@ def self.json { "alice": { "$1": "bob", - "@charlie": "david" - } + "@charlie": "david", + "@@order": ["$1"] + }, + "@@order": ["alice"] } JSON end @@ -125,8 +139,10 @@ def self.json "$1": "bob", "@xmlns": { "$": "http://some-namespace" - } - } + }, + "@@order": ["$1"] + }, + "@@order": ["alice"] } JSON end @@ -147,8 +163,10 @@ def self.json "@xmlns": { "$": "http://some-namespace", "charlie": "http://some-other-namespace" - } - } + }, + "@@order": ["$1"] + }, + "@@order": ["alice"] } JSON end @@ -170,12 +188,16 @@ def self.json "$": "http://some-namespace" }, "bob": { - "$1": "david" + "$1": "david", + "@@order": ["$1"] }, "charlie:edgar": { - "$1": "frank" - } - } + "$1": "frank", + "@@order": ["$1"] + }, + "@@order": ["bob", "charlie:edgar"] + }, + "@@order": ["alice"] } JSON end @@ -197,10 +219,13 @@ def self.json "alice": { "$1": "bob", "charlie": { - "$1": "bob2" + "$1": "bob2", + "@@order": ["$1"] }, - "$2": "bob3" - } + "$2": "bob3", + "@@order": ["$1", "charlie", "$2"] + }, + "@@order": ["alice"] } JSON end @@ -217,8 +242,10 @@ def self.json <<~JSON { "alice": { - "!1": "my comment" - } + "!1": "my comment", + "@@order": ["!1"] + }, + "@@order": ["alice"] } JSON end @@ -237,8 +264,10 @@ def self.json <<~JSON { "alice": { - "!1": " my comment " - } + "!1": " my comment ", + "@@order": ["!1"] + }, + "@@order": ["alice"] } JSON end @@ -259,16 +288,21 @@ def self.json "alice": { "bob": [ { - "$1": "charlie" + "$1": "charlie", + "@@order": ["$1"] }, { - "$1": "david" + "$1": "david", + "@@order": ["$1"] }, { - "$1": "edgar" + "$1": "edgar", + "@@order": ["$1"] } - ] - } + ], + "@@order": ["bob"] + }, + "@@order": ["alice"] } JSON end @@ -291,8 +325,10 @@ def self.json "alice": { "bob": { "@foo": "bar" - } - } + }, + "@@order": ["bob"] + }, + "@@order": ["alice"] } JSON end @@ -311,8 +347,10 @@ def self.json <<~JSON { "alice": { - "#1": "" - } + "#1": "", + "@@order": ["#1"] + }, + "@@order": ["alice"] } JSON end @@ -329,8 +367,10 @@ def self.json <<~JSON { "alice": { - "#1": "" - } + "#1": "", + "@@order": ["#1"] + }, + "@@order": ["alice"] } JSON end @@ -347,8 +387,10 @@ def self.json <<~JSON { "alice": { - "#1": " " - } + "#1": " ", + "@@order": ["#1"] + }, + "@@order": ["alice"] } JSON end @@ -366,9 +408,12 @@ def self.json { "alice": { "bob": { - "$1": "charlie" - } - } + "$1": "charlie", + "@@order": ["$1"] + }, + "@@order": ["bob"] + }, + "@@order": ["alice"] } JSON end @@ -393,8 +438,10 @@ def self.json <<~JSON { "alice": { - "$1": 1 - } + "$1": 1, + "@@order": ["$1"] + }, + "@@order": ["alice"] } JSON end @@ -418,9 +465,12 @@ def self.json "@xmlns": { "$": "http://some-other-namespace" }, - "$1": "charlie" - } - } + "$1": "charlie", + "@@order": ["$1"] + }, + "@@order": ["bob"] + }, + "@@order": ["alice"] } JSON end @@ -442,8 +492,10 @@ def self.json "@xmlns": { "bob": "http://some-other-namespace" }, - "$1": "charlie" - } + "$1": "charlie", + "@@order": ["$1"] + }, + "@@order": ["bob:alice"] } JSON end @@ -460,11 +512,14 @@ def self.json <<~JSON { "alice": { - "$1": "bob" + "$1": "bob", + "@@order": ["$1"] }, "charlie": { - "$1": "david" - } + "$1": "david", + "@@order": ["$1"] + }, + "@@order": ["alice", "charlie"] } JSON end @@ -485,14 +540,17 @@ def self.json "@xmlns": { "bob": "http://some-namespace" }, - "$1": "charlie" + "$1": "charlie", + "@@order": ["$1"] }, "david:edgar": { "@xmlns": { "david": "http://some-other-namespace" }, - "$1": "foobar" - } + "$1": "foobar", + "@@order": ["$1"] + }, + "@@order": ["bob:alice", "david:edgar"] } JSON end @@ -505,6 +563,40 @@ def self.xml end end + class CustomExampleUnsortedJson < ExampleBase + def self.test_directions + [:json2xml] + end + + def self.json + <<~JSON + { + "edgar": { + "$1": "bob", + "@@order": ["$1"] + }, + "alice": { + "charlie": { + "$1": "bob2", + "@@order": ["$1"] + }, + "$2": "bob3", + "$1": "bob", + "@@order": ["$1", "charlie", "$2"] + }, + "@@order": ["alice", "edgar"] + } + JSON + end + + def self.xml + <<-XML + bobbob2bob3 + bob + XML + end + end + def self.all constants.filter_map do |constant| c = const_get(constant) From a883074b642e65427293fcd9b0132a3db35022c7 Mon Sep 17 00:00:00 2001 From: Karol Date: Wed, 18 Oct 2023 21:00:24 +0200 Subject: [PATCH 2/2] bump version to 1.0, update Readme --- Gemfile.lock | 2 +- README.md | 4 +++- lib/dachsfisch/version.rb | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7a7ee4d..54cb81c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - dachsfisch (0.2.0) + dachsfisch (1.0.0) nokogiri (>= 1.14.1, < 2.0.0) GEM diff --git a/README.md b/README.md index 773d3f7..d3d2d02 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ The rules for converting XML documents to JSON using Badgerfish are: - CDATA sections become properties named `#1`, `#2`, etc. Please see our [examples](spec/support/examples.rb) for more details. Those rules are derived from [this list](http://dropbox.ashlock.us/open311/json-xml/). +Own additions: +- The order of nodes gets saved in `@@order` (JSON is unordered per definition) ## Installation @@ -53,7 +55,7 @@ json = Dachsfisch::XML2JSONConverter.perform(xml: xml) ### JSON-to-XML ```ruby -json = '{ "alice": { "$" : "bob" } }' +json = '{ "alice": { "$1": "bob", "@@order": ["$1"] }, "@@order": ["alice"] }' xml = Dachsfisch::JSON2XMLConverter.perform(json: json) ``` diff --git a/lib/dachsfisch/version.rb b/lib/dachsfisch/version.rb index 7ed9d64..89aa6e5 100644 --- a/lib/dachsfisch/version.rb +++ b/lib/dachsfisch/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Dachsfisch - VERSION = '0.2.0' + VERSION = '1.0.0' end