Skip to content

Commit

Permalink
Add validation for choice tags in toXml function
Browse files Browse the repository at this point in the history
  • Loading branch information
SasinduDilshara committed Nov 21, 2024
1 parent f590da4 commit c3da3be
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
9 changes: 9 additions & 0 deletions ballerina/tests/xsd_choice_array_test_with_parse_type.bal
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ function testXsdChoiceArrayWithXmlValue() returns error? {
v = parseAsType(xmlValue);
test:assertTrue(v is error);
test:assertEquals((<Error>v).message(), "'choice_XsdChoiceArrayWithXmlValue' occurs more than the max allowed times");
xml|Error toXmlResult = toXml(<XsdChoiceArrayWithXmlValue>{choice_XsdChoiceArrayWithXmlValue: {age: [13, 14, 15], salary: [11.1, 14.1, 15.1]}});
test:assertTrue(toXmlResult is error);
test:assertEquals((<Error>toXmlResult).message(), "'choice_XsdChoiceArrayWithXmlValue' occurs more than the max allowed times");
}

@Name {
Expand Down Expand Up @@ -109,11 +112,17 @@ function testXsdChoiceArrayWithXmlValue2() returns error? {
v = parseAsType(xmlValue);
test:assertTrue(v is error);
test:assertEquals((<Error>v).message(), "'choice_XsdChoiceArrayWithXmlValue2_2' occurs more than the max allowed times");
xml|Error toXmlResult = toXml(<XsdChoiceArrayWithXmlValue2>{choice_XsdChoiceArrayWithXmlValue2: {age: [13], salary: []}, choice_XsdChoiceArrayWithXmlValue2_2: {age2: [13, 14, 15], salary2: [11.1]}});
test:assertTrue(toXmlResult is error);
test:assertEquals((<Error>toXmlResult).message(), "'choice_XsdChoiceArrayWithXmlValue2_2' occurs more than the max allowed times");

xmlValue = xml `<Root><age>13</age><age>13</age><age>13</age><age2>13</age2></Root>`;
v = parseAsType(xmlValue);
test:assertTrue(v is error);
test:assertEquals((<Error>v).message(), "'choice_XsdChoiceArrayWithXmlValue2' occurs more than the max allowed times");
toXmlResult = toXml(<XsdChoiceArrayWithXmlValue2>{choice_XsdChoiceArrayWithXmlValue2: {age: [13, 14, 15], salary: [11.1, 14.1, 15.1]}});
test:assertTrue(toXmlResult is error);
test:assertEquals((<Error>toXmlResult).message(), "'choice_XsdChoiceArrayWithXmlValue2' occurs more than the max allowed times");

xmlValue = xml `<Root><age>13</age><age>13</age></Root>`;
v = parseAsType(xmlValue);
Expand Down
15 changes: 15 additions & 0 deletions ballerina/tests/xsd_choice_test_with_parse_type.bal
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ function testXsdChoiceWithXmlValue() returns error? {
test:assertEquals((<Error>v).message(), "'choice_XSDChoiceWithXmlValueRecord' occurs more than the max allowed times");
e = validate(XSDChoiceWithXmlValueRecord, xmlValue);
test:assertEquals((<Error>e).message(), "Invalid XML found: ''choice_XSDChoiceWithXmlValueRecord' occurs more than the max allowed times'");
xml|Error toXmlResult = toXml(<XSDChoiceWithXmlValueRecord>{choice_XSDChoiceWithXmlValueRecord: {age: 10, salary: 11.1}});
test:assertTrue(toXmlResult is Error);
test:assertEquals((<Error>toXmlResult).message(), "'choice_XSDChoiceWithXmlValueRecord' occurs more than the max allowed times");

xmlValue = xml `<Root><salary>11.1</salary><salary>11.1</salary></Root>`;
v = parseAsType(xmlValue);
Expand Down Expand Up @@ -210,11 +213,17 @@ function testXsdChoiceWithXmlValue2() returns error? {
v = parseAsType(xmlValue);
test:assertTrue(v is Error);
test:assertEquals((<Error>v).message(), "'choice_XSDChoiceWithXmlValueRecord2' occurs more than the max allowed times");
xml|Error toXmlResult = toXml(<XSDChoiceWithXmlValueRecord2>{choice_XSDChoiceWithXmlValueRecord2: {age: 10, salary: 11.1}, num: 3});
test:assertTrue(toXmlResult is Error);
test:assertEquals((<Error>toXmlResult).message(), "'choice_XSDChoiceWithXmlValueRecord2' occurs more than the max allowed times");

xmlValue = xml `<Root><age>10</age><num>3</num><salary>11.1</salary></Root>`;
v = parseAsType(xmlValue);
test:assertTrue(v is Error);
test:assertEquals((<Error>v).message(), "'choice_XSDChoiceWithXmlValueRecord2' occurs more than the max allowed times");
toXmlResult = toXml(<XSDChoiceWithXmlValueRecord2>{num: 3, choice_XSDChoiceWithXmlValueRecord2: {age: 10, salary: 11.1}});
test:assertTrue(toXmlResult is Error);
test:assertEquals((<Error>toXmlResult).message(), "'choice_XSDChoiceWithXmlValueRecord2' occurs more than the max allowed times");
}

@Name {
Expand Down Expand Up @@ -604,6 +613,9 @@ function testXsdChoiceWithXmlValue10() returns error? {
test:assertEquals((<Error>v2).message(), "'choice_XSDChoiceWithXmlValueRecord10_1' occurs more than the max allowed times");
e = validate(XSDChoiceWithXmlValueRecord10, xmlValue);
test:assertEquals((<Error>e).message(), "Invalid XML found: ''choice_XSDChoiceWithXmlValueRecord10_1' occurs more than the max allowed times'");
xml|Error toXmlResult = toXml(<XSDChoiceWithXmlValueRecord10>{choice_XSDChoiceWithXmlValueRecord10_1: {field1: {value1: {a: "1"}}, field2: {value2: {d: "1"}}}, choice_XSDChoiceWithXmlValueRecord10_2: {field5: {value2: {d: "2"}}}});
test:assertTrue(toXmlResult is Error);
test:assertEquals((<Error>toXmlResult).message(), "'choice_XSDChoiceWithXmlValueRecord10_1' occurs more than the max allowed times");

xmlValue = xml `<Root><field1><a>1</a></field1><field5><d>2</d></field5><field6><h>2</h></field6></Root>`;
v2 = parseAsType(xmlValue);
Expand All @@ -618,4 +630,7 @@ function testXsdChoiceWithXmlValue10() returns error? {
test:assertEquals((<Error>v2).message(), "'value2' occurs more than the max allowed times");
e = validate(XSDChoiceWithXmlValueRecord10, xmlValue);
test:assertEquals((<Error>e).message(), "Invalid XML found: ''value2' occurs more than the max allowed times'");
toXmlResult = toXml(<XSDChoiceWithXmlValueRecord10>{choice_XSDChoiceWithXmlValueRecord10_1: {field2: {value2: {d: "1", e: "1"}}}, choice_XSDChoiceWithXmlValueRecord10_2: {field5: {value2: {d: "2"}}}});
test:assertTrue(toXmlResult is Error);
test:assertEquals((<Error>toXmlResult).message(), "'value2' occurs more than the max allowed times");
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package io.ballerina.lib.data.xmldata.utils;

import io.ballerina.lib.data.xmldata.xml.xsd.ChoiceInfo;
import io.ballerina.lib.data.xmldata.xml.xsd.ElementInfo;
import io.ballerina.lib.data.xmldata.xml.xsd.ModelGroupInfo;
import io.ballerina.lib.data.xmldata.xml.xsd.SequenceInfo;
Expand Down Expand Up @@ -165,6 +166,10 @@ public static BXml traverseRecordAndGenerateXml(Object jNode, BMap<BString, BStr
BString[] orderedRecordKeysIfXsdSequencePresent = DataUtils.getOrderedRecordKeysIfXsdSequencePresent(
mapNode, DataUtils.getXsdSequencePriorityOrder(referredType, isParentSequence));

if (parentModelGroupInfo instanceof ChoiceInfo) {
validateChoiceFields(parentModelGroupInfo, jMap, elementInfoRelatedFieldNames, elementNamesMap);
}

for (BString k : orderedRecordKeysIfXsdSequencePresent) {
Object value = mapNode.get(k);
String jsonKey = k.getValue().trim();
Expand Down Expand Up @@ -259,6 +264,43 @@ options, null, getChildElementType(referredType, null),
return xNode;
}

private static void validateChoiceFields(ModelGroupInfo parentModelGroupInfo, BMap jMap,
HashMap<String, ElementInfo> elementInfoRelatedFieldNames,
HashMap<String, String> elementNamesMap) {
// TODO: Update this later for validate choices with multiple element occurences.
boolean isMeasurable = true;
int occurences = 0;

for (Object key : jMap.getKeys()) {
String jsonKey = key.toString();
Object value = jMap.get(key);
String localJsonKeyPart = jsonKey.contains(Constants.COLON) ?
jsonKey.substring(jsonKey.indexOf(Constants.COLON) + 1) : jsonKey;
String recordKey = elementNamesMap.getOrDefault(localJsonKeyPart, localJsonKeyPart);
ElementInfo elementInfo = elementInfoRelatedFieldNames.get(recordKey);
if (elementInfo != null && elementInfo.maxOccurs != 1) {
isMeasurable = false;
break;
}

if (value instanceof BArray array) {
occurences += array.size();
} else {
occurences++;
}
}

if (isMeasurable && occurences > parentModelGroupInfo.getMaxOccurs()) {
throw DiagnosticLog.error(DiagnosticErrorCode.ELEMENT_OCCURS_MORE_THAN_MAX_ALLOWED_TIMES,
parentModelGroupInfo.getFieldName());
}

if (isMeasurable && occurences < parentModelGroupInfo.getMinOccurs()) {
throw DiagnosticLog.error(DiagnosticErrorCode.ELEMENT_OCCURS_LESS_THAN_MIN_REQUIRED_TIMES,
parentModelGroupInfo.getFieldName());
}
}

private static HashMap<String, ModelGroupInfo> getModelGroupRelatedFieldNames(Type expType,
HashMap<String, String> elementNamesMap) {
Type referedType = TypeUtils.getReferredType(expType);
Expand Down

0 comments on commit c3da3be

Please sign in to comment.