diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml
index 7896a5c..b424cf2 100644
--- a/ballerina/Ballerina.toml
+++ b/ballerina/Ballerina.toml
@@ -1,16 +1,16 @@
[package]
org = "ballerina"
name = "data.xmldata"
-version = "0.1.4"
+version = "1.0.0"
authors = ["Ballerina"]
keywords = ["xml"]
repository = "https://github.com/ballerina-platform/module-ballerina-data-xmldata"
license = ["Apache-2.0"]
-distribution = "2201.9.0"
+distribution = "2201.10.0"
export = ["data.xmldata"]
[[platform.java17.dependency]]
groupId = "io.ballerina.lib"
artifactId = "data-native"
-version = "0.1.4"
-path = "../native/build/libs/data.xmldata-native-0.1.4.jar"
+version = "1.0.0"
+path = "../native/build/libs/data.xmldata-native-1.0.0-SNAPSHOT.jar"
diff --git a/ballerina/CompilerPlugin.toml b/ballerina/CompilerPlugin.toml
index 133eede..e717227 100644
--- a/ballerina/CompilerPlugin.toml
+++ b/ballerina/CompilerPlugin.toml
@@ -3,4 +3,4 @@ id = "constraint-compiler-plugin"
class = "io.ballerina.lib.data.xmldata.compiler.XmldataCompilerPlugin"
[[dependency]]
-path = "../compiler-plugin/build/libs/data.xmldata-compiler-plugin-0.1.4.jar"
+path = "../compiler-plugin/build/libs/data.xmldata-compiler-plugin-1.0.0-SNAPSHOT.jar"
diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml
index e994f42..c3c6683 100644
--- a/ballerina/Dependencies.toml
+++ b/ballerina/Dependencies.toml
@@ -5,12 +5,12 @@
[ballerina]
dependencies-toml-version = "2"
-distribution-version = "2201.9.0"
+distribution-version = "2201.10.0-20240724-114000-40e856f7"
[[package]]
org = "ballerina"
name = "data.xmldata"
-version = "0.1.4"
+version = "1.0.0"
dependencies = [
{org = "ballerina", name = "io"},
{org = "ballerina", name = "jballerina.java"},
diff --git a/ballerina/tests/fromXml_test.bal b/ballerina/tests/fromXml_test.bal
index 9785d5f..ea445bc 100644
--- a/ballerina/tests/fromXml_test.bal
+++ b/ballerina/tests/fromXml_test.bal
@@ -1620,52 +1620,6 @@ function testCommentMiddleInContent2() returns error? {
test:assertEquals(rec2.A, "John Doe");
}
-@test:Config
-function testRegexAsFieldTypeWithParseString() returns error? {
- string xmlStr = string `
- 1
- 2
- Code
-
- Kanth
-
- `;
- record {|
- string:RegExp[] A;
- string B;
- record {|
- string name;
- |} C;
- |} rec1 = check parseString(xmlStr);
- test:assertEquals(rec1.length(), 3);
- test:assertEquals(rec1.A, [1, 2]);
- test:assertEquals(rec1.B, "Code");
- test:assertEquals(rec1.C.name, "Kanth");
-}
-
-@test:Config
-function testRegexAsFieldTypeWithParseAsType() returns error? {
- xml xmlVal = xml `
- 1
- 2
- Code
-
- Kanth
-
- `;
- record {|
- string:RegExp[] A;
- string B;
- record {|
- string name;
- |} C;
- |} rec1 = check parseAsType(xmlVal);
- test:assertEquals(rec1.length(), 3);
- test:assertEquals(rec1.A, [1, 2]);
- test:assertEquals(rec1.B, "Code");
- test:assertEquals(rec1.C.name, "Kanth");
-}
-
@test:Config
function testAnydataAsRestFieldWithParseString() returns error? {
string xmlStr = string `
@@ -2812,6 +2766,128 @@ function testProjectionWithXmlAttributeForParseAsType() returns error? {
test:assertEquals(rec.A, "2");
}
+type DataN3 record {|
+ int[4] A;
+|};
+
+@test:Config {
+ groups: ["fromXmlString"]
+}
+function testXmlStringToRecordWithArrayAsFieldType() returns error? {
+ string xmlStr1 = "123";
+ DataN3 rec1 = check parseString(xmlStr1);
+ test:assertEquals(rec1.A, [1, 2, 3, 0]);
+}
+
+@test:Config {
+ groups: ["fromXml"]
+}
+function testXmlToRecordWithArrayAsFieldType() returns error? {
+ xml xmlVal1 = xml `123`;
+ DataN3 rec1 = check parseAsType(xmlVal1);
+ test:assertEquals(rec1.A, [1, 2, 3, 0]);
+}
+
+type Student record {|
+ string name;
+ int age;
+ string code = "Admitted";
+|};
+
+@test:Config
+function testXmlToRecordWithDefaultValuesForParseString1() returns error? {
+ string xmlStr = string `
+
+ Walter
+ 27
+
+ `;
+
+ Student student = check parseString(xmlStr);
+ test:assertEquals(student.name, "Walter");
+ test:assertEquals(student.age, 27);
+ test:assertEquals(student.code, "Admitted");
+}
+
+@test:Config
+function testXmlToRecordWithDefaultValuesForPasrseAsType1() returns error? {
+ xml xmlVal = xml `
+
+ Walter
+ 27
+
+ `;
+
+ Student student = check parseAsType(xmlVal);
+ test:assertEquals(student.name, "Walter");
+ test:assertEquals(student.age, 27);
+ test:assertEquals(student.code, "Admitted");
+}
+
+type University record {|
+ Student[] student;
+ string name;
+ string category = "State";
+|};
+
+@test:Config
+function testXmlToRecordWithDefaultValuesForParseString2() returns error? {
+ string xmlStr = string `
+
+
+ Walter
+ 27
+
+
+ Jessy
+ 18
+
+ Standford
+
+ `;
+
+ University university = check parseString(xmlStr);
+ test:assertEquals(university.student[0].name, "Walter");
+ test:assertEquals(university.student[0].age, 27);
+ test:assertEquals(university.student[0].code, "Admitted");
+
+ test:assertEquals(university.student[1].name, "Jessy");
+ test:assertEquals(university.student[1].age, 18);
+ test:assertEquals(university.student[1].code, "Admitted");
+
+ test:assertEquals(university.name, "Standford");
+ test:assertEquals(university.category, "State");
+}
+
+@test:Config
+function testXmlToRecordWithDefaultValuesForParseAsType2() returns error? {
+ xml xmlVal = xml `
+
+
+ Walter
+ 27
+
+
+ Jessy
+ 18
+
+ Standford
+
+ `;
+
+ University university = check parseAsType(xmlVal);
+ test:assertEquals(university.student[0].name, "Walter");
+ test:assertEquals(university.student[0].age, 27);
+ test:assertEquals(university.student[0].code, "Admitted");
+
+ test:assertEquals(university.student[1].name, "Jessy");
+ test:assertEquals(university.student[1].age, 18);
+ test:assertEquals(university.student[1].code, "Admitted");
+
+ test:assertEquals(university.name, "Standford");
+ test:assertEquals(university.category, "State");
+}
+
type RecType1 record {
string name;
@Name {
@@ -2838,15 +2914,15 @@ isolated function testElementAndAttributeInSameScopeHaveSameName() returns error
Kanth
- `;
+ `;
RecType1 rec11 = check parseString(xmlStr);
test:assertEquals(rec11.name, "Kanth");
test:assertEquals(rec11.duplicateName, "Kevin");
RecType2 rec12 = check parseString(xmlStr);
test:assertEquals(rec12.name.\#content, "Kanth");
- test:assertEquals(rec12.duplicateName, "Kevin");
-
+ test:assertEquals(rec12.duplicateName, "Kevin");
+
xml xmlVal = xml `
Kanth
@@ -2858,7 +2934,7 @@ isolated function testElementAndAttributeInSameScopeHaveSameName() returns error
RecType2 rec22 = check parseAsType(xmlVal);
test:assertEquals(rec22.name.\#content, "Kanth");
- test:assertEquals(rec22.duplicateName, "Kevin");
+ test:assertEquals(rec22.duplicateName, "Kevin");
}
type RecNs3 record {|
@@ -2888,7 +2964,7 @@ isolated function testElementWithDifferentNamespace() returns error? {
RecNs3 rec = check parseString(xmlStr);
test:assertEquals(rec.name, "Kevin");
test:assertEquals(rec.duplicateName, "Kanth");
-
+
xml xmlVal = xml `
Kevin
@@ -2959,28 +3035,6 @@ function testXmlToRecordNegative4() {
test:assertEquals((rec1).message(), "expected 'int' value for the field 'A' found 'array' value");
}
-type DataN3 record {|
- int[4] A;
-|};
-
-@test:Config {
- groups: ["fromXmlString"]
-}
-function testXmlStringToRecordNegative5() {
- string xmlStr1 = "123";
- DataN3|error rec1 = parseString(xmlStr1);
- test:assertEquals((rec1).message(), "array size is not compatible with the expected size");
-}
-
-@test:Config {
- groups: ["fromXml"]
-}
-function testXmlToRecordNegative5() {
- xml xmlVal1 = xml `123`;
- DataN3|error rec1 = parseAsType(xmlVal1);
- test:assertEquals((rec1).message(), "array size is not compatible with the expected size");
-}
-
type DataN4 record {|
string...;
|};
@@ -3329,6 +3383,88 @@ function testInvalidNamespaceInOpenRecordForParseAsType2() {
test:assertEquals((err).message(), "undefined field 'name' in record 'data.xmldata:AuthorOpen'");
}
+@test:Config
+function testRegexAsFieldTypeWithParseStringNegative1() {
+ string xmlStr = string `
+ 1
+ 2
+ Code
+
+ Kanth
+
+ `;
+ record {|
+ string:RegExp[] A;
+ string B;
+ record {|
+ string name;
+ |} C;
+ |}|Error err = parseString(xmlStr);
+ test:assertTrue(err is error);
+ test:assertEquals((err).message(), "unsupported input type");
+}
+
+@test:Config
+function testRegexAsFieldTypeWithParseStringNegative2() {
+ string xmlStr = string `
+ 1
+ Code
+
+ Kanth
+
+ `;
+ record {|
+ string:RegExp A;
+ string B;
+ record {|
+ string name;
+ |} C;
+ |}|Error err = parseString(xmlStr);
+ test:assertTrue(err is error);
+ test:assertEquals((err).message(), "unsupported input type");
+}
+
+@test:Config
+function testRegexAsFieldTypeWithParseAsType() {
+ xml xmlVal = xml `
+ 1
+ 2
+ Code
+
+ Kanth
+
+ `;
+ record {|
+ string:RegExp[] A;
+ string B;
+ record {|
+ string name;
+ |} C;
+ |}|error err = parseAsType(xmlVal);
+ test:assertTrue(err is error);
+ test:assertEquals((err).message(), "unsupported input type");
+}
+
+@test:Config
+function testRegexAsFieldTypeWithParseAsType2() {
+ xml xmlVal = xml `
+ 1
+ Code
+
+ Kanth
+
+ `;
+ record {|
+ string:RegExp A;
+ string B;
+ record {|
+ string name;
+ |} C;
+ |}|error err = parseAsType(xmlVal);
+ test:assertTrue(err is error);
+ test:assertEquals((err).message(), "unsupported input type");
+}
+
type RecTypeDup1 record {
string name;
@Name {
@@ -3377,7 +3513,7 @@ isolated function testDuplicateField() {
RecTypeDup2|Error err3 = parseString(xmlStr2);
test:assertTrue(err3 is Error);
test:assertEquals(( err3).message(), "duplicate field 'name'");
-
+
xml xmlVal2 = xml `
Kanth
diff --git a/ballerina/tests/from_xml_with_options.bal b/ballerina/tests/from_xml_with_options.bal
index 93689fa..881bd41 100644
--- a/ballerina/tests/from_xml_with_options.bal
+++ b/ballerina/tests/from_xml_with_options.bal
@@ -294,7 +294,7 @@ function testDisableProjectionInArrayForParseStringNegative() {
test:assertEquals((rec).message(), "array size is not compatible with the expected size");
}
-@test:Config
+@test:Config
function testDisableProjectionInArrayForParseAsTypeNegative() {
xml xmlVal1 = xml `
1
diff --git a/build-config/resources/Ballerina.toml b/build-config/resources/Ballerina.toml
index 741191d..5f14962 100644
--- a/build-config/resources/Ballerina.toml
+++ b/build-config/resources/Ballerina.toml
@@ -6,7 +6,7 @@ authors = ["Ballerina"]
keywords = ["xml"]
repository = "https://github.com/ballerina-platform/module-ballerina-data-xmldata"
license = ["Apache-2.0"]
-distribution = "2201.9.0"
+distribution = "2201.10.0"
export = ["data.xmldata"]
[[platform.java17.dependency]]
diff --git a/gradle.properties b/gradle.properties
index 78a2cb2..89a09c9 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,7 +1,7 @@
org.gradle.caching=true
group=io.ballerina.lib
-version=0.1.5-SNAPSHOT
-ballerinaLangVersion=2201.9.0
+version=1.0.0-SNAPSHOT
+ballerinaLangVersion=2201.10.0-20240724-114000-40e856f7
checkstyleToolVersion=10.12.0
puppycrawlCheckstyleVersion=10.12.0
diff --git a/native/src/main/java/io/ballerina/lib/data/xmldata/utils/Constants.java b/native/src/main/java/io/ballerina/lib/data/xmldata/utils/Constants.java
index 04830ac..41eaf87 100644
--- a/native/src/main/java/io/ballerina/lib/data/xmldata/utils/Constants.java
+++ b/native/src/main/java/io/ballerina/lib/data/xmldata/utils/Constants.java
@@ -61,4 +61,6 @@ private Constants() {}
public static final BString ALLOW_DATA_PROJECTION = StringUtils.fromString("allowDataProjection");
public static final String RECORD_FIELD_NAME_ESCAPE_CHAR_REGEX = "[^a-zA-Z\\d\s_]";
public static final String NS_ANNOT_NOT_DEFINED = "$$ns_annot_not_defined$$";
+ public static final String REGEXP_MODULE_NAME = "lang.regexp";
+ public static final String REGEXP_TYPE_NAME = "RegExp";
}
diff --git a/native/src/main/java/io/ballerina/lib/data/xmldata/utils/DataUtils.java b/native/src/main/java/io/ballerina/lib/data/xmldata/utils/DataUtils.java
index 86fd06f..153c16d 100644
--- a/native/src/main/java/io/ballerina/lib/data/xmldata/utils/DataUtils.java
+++ b/native/src/main/java/io/ballerina/lib/data/xmldata/utils/DataUtils.java
@@ -21,6 +21,7 @@
import io.ballerina.lib.data.xmldata.FromString;
import io.ballerina.lib.data.xmldata.xml.QualifiedName;
import io.ballerina.lib.data.xmldata.xml.QualifiedNameMap;
+import io.ballerina.runtime.api.Module;
import io.ballerina.runtime.api.PredefinedTypes;
import io.ballerina.runtime.api.TypeTags;
import io.ballerina.runtime.api.creators.TypeCreator;
@@ -30,6 +31,7 @@
import io.ballerina.runtime.api.types.Field;
import io.ballerina.runtime.api.types.MapType;
import io.ballerina.runtime.api.types.RecordType;
+import io.ballerina.runtime.api.types.ReferenceType;
import io.ballerina.runtime.api.types.Type;
import io.ballerina.runtime.api.types.UnionType;
import io.ballerina.runtime.api.utils.StringUtils;
@@ -213,10 +215,6 @@ private static String getModifiedName(Map fieldAnnotation, Stri
return attributeName;
}
- public static BArray createNewAnydataList(Type type) {
- return ValueCreator.createArrayValue(getArrayTypeFromElementType(type));
- }
-
public static QualifiedName getElementName(QName qName) {
return new QualifiedName(qName.getNamespaceURI(), qName.getLocalPart(), qName.getPrefix());
}
@@ -238,33 +236,16 @@ public static Object convertStringToExpType(BString value, Type expType) {
return result;
}
- public static void validateRequiredFields(BMap currentMapValue, XmlAnalyzerData analyzerData) {
- Map fields = analyzerData.fieldHierarchy.peek().getMembers();
- for (QualifiedName key : fields.keySet()) {
- // Validate required array size
- Field field = fields.get(key);
- String fieldName = field.getFieldName();
- if (field.getFieldType().getTag() == TypeTags.ARRAY_TAG) {
- ArrayType arrayType = (ArrayType) field.getFieldType();
- if (arrayType.getSize() != -1
- && arrayType.getSize() != ((BArray) currentMapValue.get(
- StringUtils.fromString(fieldName))).getLength()) {
- throw DiagnosticLog.error(DiagnosticErrorCode.ARRAY_SIZE_MISMATCH);
- }
- }
-
- if (!SymbolFlags.isFlagOn(field.getFlags(), SymbolFlags.OPTIONAL)
- && !currentMapValue.containsKey(StringUtils.fromString(fieldName))) {
- throw DiagnosticLog.error(DiagnosticErrorCode.REQUIRED_FIELD_NOT_PRESENT, fieldName);
+ public static void validateRequiredFields(XmlAnalyzerData analyzerData) {
+ for (Field field : analyzerData.fieldHierarchy.peek().getMembers().values()) {
+ if (SymbolFlags.isFlagOn(field.getFlags(), SymbolFlags.REQUIRED)) {
+ throw DiagnosticLog.error(DiagnosticErrorCode.REQUIRED_FIELD_NOT_PRESENT, field.getFieldName());
}
}
- Map attributes = analyzerData.attributeHierarchy.peek().getMembers();
- for (QualifiedName key : attributes.keySet()) {
- Field field = attributes.get(key);
- String fieldName = field.getFieldName();
- if (!SymbolFlags.isFlagOn(field.getFlags(), SymbolFlags.OPTIONAL)) {
- throw DiagnosticLog.error(DiagnosticErrorCode.REQUIRED_ATTRIBUTE_NOT_PRESENT, fieldName);
+ for (Field attribute : analyzerData.attributeHierarchy.peek().getMembers().values()) {
+ if (!SymbolFlags.isFlagOn(attribute.getFlags(), SymbolFlags.OPTIONAL)) {
+ throw DiagnosticLog.error(DiagnosticErrorCode.REQUIRED_ATTRIBUTE_NOT_PRESENT, attribute.getFieldName());
}
}
}
@@ -277,27 +258,15 @@ public static boolean isStringValueAssignable(int typeTag) {
return typeTag == TypeTags.STRING_TAG || typeTag == TypeTags.ANYDATA_TAG || typeTag == TypeTags.JSON_TAG;
}
- public static ArrayType getValidArrayType(Type type) {
- return switch (type.getTag()) {
- case TypeTags.ARRAY_TAG -> (ArrayType) type;
- case TypeTags.ANYDATA_TAG -> PredefinedTypes.TYPE_ANYDATA_ARRAY;
- case TypeTags.JSON_TAG -> PredefinedTypes.TYPE_JSON_ARRAY;
- default -> null;
- };
- }
-
- public static ArrayType getArrayTypeFromElementType(Type type) {
+ public static BArray createArrayValue(Type type) {
return switch (type.getTag()) {
- case TypeTags.ARRAY_TAG -> TypeCreator.createArrayType(((ArrayType) type).getElementType());
- case TypeTags.JSON_TAG -> PredefinedTypes.TYPE_JSON_ARRAY;
- case TypeTags.INT_TAG, TypeTags.FLOAT_TAG, TypeTags.STRING_TAG, TypeTags.BOOLEAN_TAG, TypeTags.BYTE_TAG,
- TypeTags.DECIMAL_TAG, TypeTags.RECORD_TYPE_TAG, TypeTags.MAP_TAG, TypeTags.OBJECT_TYPE_TAG,
- TypeTags.XML_TAG, TypeTags.NULL_TAG -> TypeCreator.createArrayType(type);
- case TypeTags.TYPE_REFERENCED_TYPE_TAG -> getArrayTypeFromElementType(TypeUtils.getReferredType(type));
- default -> PredefinedTypes.TYPE_ANYDATA_ARRAY;
+ case TypeTags.ARRAY_TAG -> ValueCreator.createArrayValue((ArrayType) type);
+ case TypeTags.JSON_TAG -> ValueCreator.createArrayValue(PredefinedTypes.TYPE_JSON_ARRAY);
+ case TypeTags.ANYDATA_TAG -> ValueCreator.createArrayValue(PredefinedTypes.TYPE_ANYDATA_ARRAY);
+ case TypeTags.TYPE_REFERENCED_TYPE_TAG -> createArrayValue(TypeUtils.getReferredType(type));
+ default -> throw new IllegalStateException("Unexpected value: " + type.getTag());
};
}
-
public static MapType getMapTypeFromConstraintType(Type constraintType) {
return switch (constraintType.getTag()) {
case TypeTags.MAP_TAG -> (MapType) constraintType;
@@ -312,15 +281,18 @@ public static MapType getMapTypeFromConstraintType(Type constraintType) {
}
public static void updateExpectedTypeStacks(RecordType recordType, XmlAnalyzerData analyzerData) {
- analyzerData.attributeHierarchy.push(new QualifiedNameMap(getAllAttributesInRecordType(recordType)));
- analyzerData.fieldHierarchy.push(new QualifiedNameMap(getAllFieldsInRecordType(recordType, analyzerData)));
+ analyzerData.attributeHierarchy.push(new QualifiedNameMap<>(getAllAttributesInRecordType(recordType)));
+ analyzerData.fieldHierarchy.push(new QualifiedNameMap<>(getAllFieldsInRecordType(recordType, analyzerData)));
+ analyzerData.visitedFieldHierarchy.push(new QualifiedNameMap<>(new HashMap<>()));
analyzerData.restTypes.push(recordType.getRestFieldType());
}
- public static void removeExpectedTypeStacks(XmlAnalyzerData analyzerData) {
- analyzerData.attributeHierarchy.pop();
+ public static void popExpectedTypeStacks(XmlAnalyzerData analyzerData) {
analyzerData.fieldHierarchy.pop();
+ analyzerData.visitedFieldHierarchy.pop();
analyzerData.restTypes.pop();
+ analyzerData.attributeHierarchy.pop();
+ analyzerData.arrayIndexes.pop();
}
public static boolean isAnydataOrJson(int typeTag) {
@@ -850,6 +822,27 @@ private static String addAttributeToRecord(BString prefix, BString uri, String k
return prefix.getValue().concat(Constants.COLON).concat(key);
}
+ public static boolean isRegExpType(Type type) {
+ Module module = type.getPackage();
+ if (module == null) {
+ return false;
+ }
+
+ String moduleName = module.getName();
+ String typeName = type.getName();
+ if (typeName == null || moduleName == null) {
+ return false;
+ }
+ if (moduleName.equals(Constants.REGEXP_MODULE_NAME) && typeName.equals(Constants.REGEXP_TYPE_NAME)) {
+ return true;
+ }
+
+ if (type.getTag() == TypeTags.TYPE_REFERENCED_TYPE_TAG) {
+ return isRegExpType(((ReferenceType) type).getReferredType());
+ }
+ return false;
+ }
+
private static boolean isNamespaceAnnotationKey(String key) {
return key.startsWith(Constants.MODULE_NAME) && key.endsWith(Constants.NAMESPACE);
}
@@ -870,8 +863,10 @@ private static boolean isAttributeAnnotationKey(String key) {
public static class XmlAnalyzerData {
public final Stack