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/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/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
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)