Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove some limitation from the output of toRecord() #418

Merged
merged 22 commits into from
Apr 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
632aa49
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 23, 2022
4f4bf86
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 23, 2022
503f24d
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 23, 2022
7e6a730
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 23, 2022
bc10245
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 24, 2022
fc7dbd4
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 24, 2022
e8128cd
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 24, 2022
594dfe2
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 25, 2022
390bff6
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 27, 2022
166f057
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 27, 2022
ebc382b
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 27, 2022
70b4391
Merge https://github.com/ballerina-platform/module-ballerina-xmldata …
kalaiyarasiganeshalingam Mar 28, 2022
c0cdd19
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 30, 2022
0d1b7d9
Update output of toRecord() impl
kalaiyarasiganeshalingam Mar 30, 2022
af822c0
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 30, 2022
b272805
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 30, 2022
669a811
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 30, 2022
a838971
[Automated] Update the native jar versions
kalaiyarasiganeshalingam Mar 30, 2022
124f122
Remove arrayEntryTag and attributePrefix initialization
kalaiyarasiganeshalingam Mar 30, 2022
cb281eb
Remove double quotes
kalaiyarasiganeshalingam Mar 31, 2022
f60ad19
Remove new JSON option initialization
kalaiyarasiganeshalingam Apr 12, 2022
1f2c6c3
Update the change log file
kalaiyarasiganeshalingam Apr 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
org = "ballerina"
name = "xmldata"
version = "2.2.1"
version = "2.2.2"
authors = ["Ballerina"]
keywords = ["xml", "json"]
repository = "https://github.com/ballerina-platform/module-ballerina-xmldata"
Expand All @@ -10,4 +10,4 @@ license = ["Apache-2.0"]
distribution = "2201.0.1"

[[platform.java11.dependency]]
path = "../native/build/libs/xmldata-native-2.2.1.jar"
path = "../native/build/libs/xmldata-native-2.2.2-SNAPSHOT.jar"
2 changes: 1 addition & 1 deletion ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ modules = [
[[package]]
org = "ballerina"
name = "xmldata"
version = "2.2.1"
version = "2.2.2"
dependencies = [
{org = "ballerina", name = "jballerina.java"},
{org = "ballerina", name = "test"}
Expand Down
84 changes: 84 additions & 0 deletions ballerina/tests/xml_from_json_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -769,3 +769,87 @@ isolated function testWithAttribute3() {
test:assertFail("failed to convert json to xml");
}
}

type Order record {
Invoice Invoice;
};

type Invoice record {
PurchesedItems PurchesedItems;
Address1 Address;
string _xmlns?;
string _xmlns\:ns?;
string _attr?;
string _ns\:attr?;
};

type PurchesedItems record {
Purchase[] PLine;
};

type Purchase record {
string|ItemCode ItemCode;
int Count;
};

type ItemCode record {
string _discount;
string \#content;
};

type Address1 record {
string StreetAddress;
string City;
int Zip;
string Country;
string _xmlns?;
};

@test:Config {
groups: ["fromJson"]
}
isolated function testfromjsonwithRecord() {
Order data = {
Invoice: {
PurchesedItems: {
PLine: [
{ItemCode: "223345", Count: 10},
{ItemCode: "223300", Count: 7},
{
ItemCode: {_discount: "22%", \#content: "200777"},
Count: 7
}
]
},
Address: {
StreetAddress: "20, Palm grove, Colombo 3",
City: "Colombo",
Zip: 300,
Country: "LK"
},
_attr: "attr-val",
_xmlns: "example.com",
_xmlns\:ns: "ns.com"
}
};
string expected = "<Invoice xmlns=\"example.com\" xmlns:ns=\"ns.com\" attr=\"attr-val\">" +
"<PurchesedItems>" +
"<PLine><ItemCode>223345</ItemCode><Count>10</Count></PLine>" +
"<PLine><ItemCode>223300</ItemCode><Count>7</Count></PLine>" +
"<PLine><ItemCode discount=\"22%\">200777</ItemCode><Count>7</Count></PLine>" +
"</PurchesedItems>" +
"<Address>" +
"<StreetAddress>20, Palm grove, Colombo 3</StreetAddress>" +
"<City>Colombo</City>" +
"<Zip>300</Zip>" +
"<Country>LK</Country>" +
"</Address>" +
"</Invoice>";
json jsonData = data.toJson();
xml?|error result = fromJson(jsonData, {attributePrefix: "_"});
if result is xml {
test:assertEquals(result.toString(), expected.toString());
} else {
test:assertFail("failed to convert json to xml");
}
}
54 changes: 10 additions & 44 deletions ballerina/tests/xml_to_record_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -52,40 +52,6 @@ isolated function testToRecordWithEscapedString() returns error? {
test:assertEquals(actual, expected, msg = "testToRecordWithEscapedString result incorrect");
}

type Order record {
Invoice Invoice;
};

type Invoice record {
PurchesedItems PurchesedItems;
Address1 Address;
string _xmlns?;
string _xmlns_ns?;
string _attr?;
string _ns_attr?;
};

type PurchesedItems record {
Purchase[] PLine;
};

type Purchase record {
string|ItemCode ItemCode;
int Count;
};

type ItemCode record {
string _discount;
};

type Address1 record {
string StreetAddress;
string City;
int Zip;
string Country;
string _xmlns?;
};

xml e2 = xml `<Invoice xmlns="example.com" attr="attr-val" xmlns:ns="ns.com" ns:attr="ns-attr-val">
<PurchesedItems>
<PLine><ItemCode>223345</ItemCode><Count>10</Count></PLine>
Expand All @@ -111,7 +77,7 @@ function testToRecordComplexXmlElement() returns error? {
{ItemCode: "223345", Count: 10},
{ItemCode: "223300", Count: 7},
{
ItemCode: {"_discount": "22%", "#content": "200777"},
ItemCode: {_discount: "22%", \#content: "200777"},
Count: 7
}
]
Expand All @@ -124,9 +90,9 @@ function testToRecordComplexXmlElement() returns error? {
_xmlns: ""
},
_xmlns: "example.com",
_xmlns_ns: "ns.com",
_xmlns\:ns: "ns.com",
_attr: "attr-val",
_ns_attr: "ns-attr-val"
_ns\:attr: "ns-attr-val"
}
};
Order actual = check toRecord(e2);
Expand All @@ -144,7 +110,7 @@ function testToRecordComplexXmlElementWithoutPreserveNamespaces() returns error?
{ItemCode: "223345", Count: 10},
{ItemCode: "223300", Count: 7},
{
ItemCode: {"_discount": "22%", "#content": "200777"},
ItemCode: {_discount: "22%", \#content: "200777"},
Count: 7
}
]
Expand Down Expand Up @@ -264,8 +230,8 @@ type r2 record {
};

type Root2 record {
string _xmlns_ns;
string _ns_x;
string _xmlns\:ns;
string _ns\:x;
string _x;
};

Expand All @@ -277,8 +243,8 @@ isolated function testToRecordWithMultipleAttributesAndNamespaces() returns Erro

r2 expected = {
Root: {
_xmlns_ns: "ns.com",
_ns_x: "y",
_xmlns\:ns: "ns.com",
_ns\:x: "y",
_x: "z"
}
};
Expand Down Expand Up @@ -476,7 +442,7 @@ type BookStore2 record {
Address3 address;
Codes codes;
string _status;
string _xmlns_ns0;
string _xmlns\:ns0;
};

@test:Config {
Expand Down Expand Up @@ -515,7 +481,7 @@ isolated function testToRecordWithNamespaces() returns error? {
codes: {
item: [4, 8, 9]
},
_xmlns_ns0: "http://sample.com/test",
_xmlns\:ns0: "http://sample.com/test",
_status: "online"
}
};
Expand Down
64 changes: 36 additions & 28 deletions ballerina/xmldata.bal
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public type JsonOptions record {
# successfully converted or else an `xmldata:Error`
public isolated function fromJson(json jsonValue, JsonOptions options = {}) returns xml?|Error {
if !isSingleNode(jsonValue) {
return getElement("root", check traverseNode(jsonValue, {}, options),
check getAttributesMap(jsonValue, options = options));
return getElement("root", check traverseNode(jsonValue, {}, options), options,
check getAttributesMap(jsonValue, options));
} else {
map<json>|error jMap = jsonValue.ensureType();
if jMap is map<json> {
Expand All @@ -54,15 +54,15 @@ public isolated function fromJson(json jsonValue, JsonOptions options = {}) retu
}
json value = jMap.toArray()[0];
if value is json[] {
return getElement("root", check traverseNode(value, {}, options, jMap.keys()[0]),
check getAttributesMap(value, options = options));
return getElement("root", check traverseNode(value, {}, options, jMap.keys()[0]), options,
check getAttributesMap(value, options));
} else {
string key = jMap.keys()[0];
if key == CONTENT {
return xml:createText(value.toString());
}
return getElement(jMap.keys()[0], check traverseNode(value, {}, options),
check getAttributesMap(value, options = options));
return getElement(jMap.keys()[0], check traverseNode(value, {}, options), options,
check getAttributesMap(value, options));
}
}
if jsonValue !is null {
Expand All @@ -73,23 +73,22 @@ public isolated function fromJson(json jsonValue, JsonOptions options = {}) retu
}
}

isolated function traverseNode(json jNode, map<string> parentNamespaces, JsonOptions options = {},
isolated function traverseNode(json jNode, map<string> parentNamespaces, JsonOptions options,
string? key = ()) returns xml|Error {
string arrayEntryTag = options.arrayEntryTag == "" ? "item" : options.arrayEntryTag;
string attributePrefix = options.attributePrefix == "" ? "@" : options.attributePrefix;
xml xNode = xml ``;
if jNode is map<json> {
foreach [string, json] [k, v] in jNode.entries() {
if !k.startsWith(attributePrefix) {
if !k.startsWith(options.attributePrefix) {
if k == CONTENT {
xNode += xml:createText(v.toString());
} else if v is json[] {
xml node = check traverseNode(v, check getNamespacesMap(v, parentNamespaces, options), options, k);
xml node = check traverseNode(v, check getNamespacesMap(v, options, parentNamespaces), options, k);
xNode += node;
} else {
xml node = check getElement(k, check traverseNode(v,
check getNamespacesMap(v, parentNamespaces, options), options),
check getAttributesMap(v, parentNamespaces, options = options));
check getNamespacesMap(v, options, parentNamespaces), options),
options,
check getAttributesMap(v, options, parentNamespaces));
xNode += node;
}
}
Expand All @@ -100,11 +99,12 @@ isolated function traverseNode(json jNode, map<string> parentNamespaces, JsonOpt
if (key is string) {
arrayEntryTagKey = key;
} else {
arrayEntryTagKey = arrayEntryTag;
arrayEntryTagKey = options.arrayEntryTag;
}
xml item = check getElement(arrayEntryTagKey, check traverseNode(i,
check getNamespacesMap(i, parentNamespaces, options)),
check getAttributesMap(i, parentNamespaces, options = options));
check getNamespacesMap(i, options, parentNamespaces), options),
options,
check getAttributesMap(i, options, parentNamespaces));
xNode += item;
}
} else {
Expand All @@ -124,9 +124,9 @@ isolated function isSingleNode(json node) returns boolean {
return true;
}

isolated function getElement(string name, xml children, map<string> attributes = {}, JsonOptions options = {})
isolated function getElement(string name, xml children, JsonOptions options, map<string> attributes = {})
returns xml|Error {
string attributePrefix = options.attributePrefix == "" ? "@" : options.attributePrefix;
string attributePrefix = options.attributePrefix;
xml:Element element;
int? index = name.indexOf(":");
if index is int {
Expand All @@ -149,9 +149,9 @@ isolated function getElement(string name, xml children, map<string> attributes =
return element;
}

isolated function getAttributesMap(json jTree, map<string> parentNamespaces = {}, JsonOptions options = {})
isolated function getAttributesMap(json jTree, JsonOptions options, map<string> parentNamespaces = {})
returns map<string>|Error {
string attributePrefix = options.attributePrefix == "" ? "@" : options.attributePrefix;
string attributePrefix = options.attributePrefix;
map<string> attributes = parentNamespaces.clone();
map<json>|error attr = jTree.ensureType();
if attr is map<json> {
Expand All @@ -160,9 +160,12 @@ isolated function getAttributesMap(json jTree, map<string> parentNamespaces = {}
if v is map<json> || v is json[] {
return error Error("attribute cannot be an object or array");
}
if k.startsWith(attributePrefix + "xmlns") {
string prefix = k.substring(<int>k.indexOf(":") + 1);
attributes[string `{${XMLNS_NAMESPACE_URI}}${prefix}`] = v.toString();
int? index = k.indexOf(":");
if index is int {
if k.startsWith(attributePrefix + "xmlns") {
string prefix = k.substring(index + 1);
attributes[string `{${XMLNS_NAMESPACE_URI}}${prefix}`] = v.toString();
}
} else {
attributes[k.substring(1)] = v.toString();
}
Expand All @@ -172,20 +175,25 @@ isolated function getAttributesMap(json jTree, map<string> parentNamespaces = {}
return attributes;
}

isolated function getNamespacesMap(json jTree, map<string> parentNamespaces = {}, JsonOptions options = {})
isolated function getNamespacesMap(json jTree, JsonOptions options, map<string> parentNamespaces = {})
returns map<string>|Error {
string attributePrefix = options.attributePrefix == "" ? "@" : options.attributePrefix;
string attributePrefix = options.attributePrefix;
map<string> namespaces = parentNamespaces.clone();
map<json>|error attr = jTree.ensureType();
if attr is map<json> {
foreach [string, json] [k, v] in attr.entries() {
if k.startsWith(attributePrefix) {
if v is map<json> || v is json[] {
return error Error("attribute cannot be an object or array");
return error Error("attribute cannot be an object or array.");
}
if k.startsWith(attributePrefix + "xmlns") {
string prefix = k.substring(<int>k.indexOf(":") + 1);
namespaces[string `{${XMLNS_NAMESPACE_URI}}${prefix}`] = v.toString();
int? index = k.indexOf(":");
if index is int {
string prefix = k.substring(index + 1);
namespaces[string `{${XMLNS_NAMESPACE_URI}}${prefix}`] = v.toString();
} else {
namespaces[string `{${XMLNS_NAMESPACE_URI}}`] = v.toString();
}
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- [[2406] Add `toRecord` function which converts an XML to a Record](https://github.com/ballerina-platform/ballerina-standard-library/issues/2406)

### Fixed
- [Fix the limitations of using the colon in the output of the `toRecord`](https://github.com/ballerina-platform/module-ballerina-xmldata/pull/418)

## [2.1.0] - 2021-12-13

### Added
- [Add `toRecord` function which converts an XML to a Record](https://github.com/ballerina-platform/ballerina-standard-library/issues/2406)

## [1.1.0-alpha6] - 2021-04-02

Expand Down
Loading