From c75203ce3c4e29d082c9e0015543e4ba7075ce44 Mon Sep 17 00:00:00 2001
From: prakanth <50439067+prakanth97@users.noreply.github.com>
Date: Sun, 7 Jul 2024 12:58:26 +0530
Subject: [PATCH 1/3] [Automated] Update the native jar versions
---
ballerina/Ballerina.toml | 6 +++---
ballerina/CompilerPlugin.toml | 2 +-
ballerina/Dependencies.toml | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml
index 6e20373..5c74e53 100644
--- a/ballerina/Ballerina.toml
+++ b/ballerina/Ballerina.toml
@@ -1,7 +1,7 @@
[package]
org = "ballerina"
name = "data.xmldata"
-version = "0.1.2"
+version = "0.1.3"
authors = ["Ballerina"]
keywords = ["xml"]
repository = "https://github.com/ballerina-platform/module-ballerina-data-xmldata"
@@ -12,5 +12,5 @@ export = ["data.xmldata"]
[[platform.java17.dependency]]
groupId = "io.ballerina.lib"
artifactId = "data-native"
-version = "0.1.2"
-path = "../native/build/libs/data.xmldata-native-0.1.2.jar"
+version = "0.1.3"
+path = "../native/build/libs/data.xmldata-native-0.1.3-SNAPSHOT.jar"
diff --git a/ballerina/CompilerPlugin.toml b/ballerina/CompilerPlugin.toml
index 0e62175..2299c31 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.2.jar"
+path = "../compiler-plugin/build/libs/data.xmldata-compiler-plugin-0.1.3-SNAPSHOT.jar"
diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml
index bcfbdef..d920883 100644
--- a/ballerina/Dependencies.toml
+++ b/ballerina/Dependencies.toml
@@ -10,7 +10,7 @@ distribution-version = "2201.9.0"
[[package]]
org = "ballerina"
name = "data.xmldata"
-version = "0.1.2"
+version = "0.1.3"
dependencies = [
{org = "ballerina", name = "io"},
{org = "ballerina", name = "jballerina.java"},
From 6109556bfd65b285eef24aa6560c4526bbdd7dd3 Mon Sep 17 00:00:00 2001
From: prakanth <50439067+prakanth97@users.noreply.github.com>
Date: Mon, 8 Jul 2024 17:47:03 +0530
Subject: [PATCH 2/3] Handle attribute and element with same name
---
ballerina/tests/fromXml_test.bal | 128 ++++++++++++++++++
ballerina/tests/toXml_test.bal | 2 +-
.../lib/data/xmldata/compiler/Constants.java | 1 +
.../compiler/XmldataRecordFieldValidator.java | 11 +-
.../compiler/objects/QualifiedName.java | 6 +-
.../lib/data/xmldata/utils/DataUtils.java | 33 ++++-
.../lib/data/xmldata/xml/QualifiedName.java | 26 +++-
.../data/xmldata/xml/QualifiedNameMap.java | 24 +++-
.../lib/data/xmldata/xml/XmlParser.java | 29 ++--
9 files changed, 231 insertions(+), 29 deletions(-)
diff --git a/ballerina/tests/fromXml_test.bal b/ballerina/tests/fromXml_test.bal
index 1163c0e..7ae07bc 100644
--- a/ballerina/tests/fromXml_test.bal
+++ b/ballerina/tests/fromXml_test.bal
@@ -2812,6 +2812,75 @@ function testProjectionWithXmlAttributeForParseAsType() returns error? {
test:assertEquals(rec.A, "2");
}
+type RecType record {
+ string name;
+ @Name {
+ value: "name"
+ }
+ @Attribute
+ string duplicateName;
+};
+
+@test:Config
+isolated function testElementAndAttributeInSameScopeHaveSameName() returns error? {
+ string xmlStr = string `
+
+ Kanth
+
+ `;
+ RecType rec = check parseString(xmlStr);
+ test:assertEquals(rec.name, "Kanth");
+ test:assertEquals(rec.duplicateName, "Kevin");
+
+ xml xmlVal = xml `
+
+ Kanth
+
+ `;
+ RecType rec2 = check parseAsType(xmlVal);
+ test:assertEquals(rec2.name, "Kanth");
+ test:assertEquals(rec2.duplicateName, "Kevin");
+}
+
+type RecNs3 record {|
+ @Namespace {
+ prefix: "ns1",
+ uri: "example1.com"
+ }
+ string name;
+ @Name {
+ value: "name"
+ }
+ @Namespace {
+ prefix: "ns2",
+ uri: "example2.com"
+ }
+ string duplicateName;
+|};
+
+@test:Config
+isolated function testElementWithDifferentNamespace() returns error? {
+ string xmlStr = string `
+
+ Kevin
+ Kanth
+
+ `;
+ RecNs3 rec = check parseString(xmlStr);
+ test:assertEquals(rec.name, "Kevin");
+ test:assertEquals(rec.duplicateName, "Kanth");
+
+ xml xmlVal = xml `
+
+ Kevin
+ Kanth
+
+ `;
+ RecNs3 rec2 = check parseAsType(xmlVal);
+ test:assertEquals(rec2.name, "Kevin");
+ test:assertEquals(rec2.duplicateName, "Kanth");
+}
+
// Negative cases
type DataN1 record {|
int A;
@@ -3240,3 +3309,62 @@ function testInvalidNamespaceInOpenRecordForParseAsType2() {
test:assertTrue(err is error);
test:assertEquals((err).message(), "undefined field 'name' in record 'data.xmldata:AuthorOpen'");
}
+
+type RecTypeDup1 record {
+ string name;
+ @Name {
+ value: "name"
+ }
+ string duplicateName;
+};
+
+type RecTypeDup2 record {
+ @Namespace {
+ prefix: "ns",
+ uri: "example.com"
+ }
+ string name;
+ @Name {
+ value: "name"
+ }
+ string duplicateName;
+};
+
+@test:Config
+isolated function testDuplicateField() {
+ string xmlStr = string `
+
+ Kanth
+
+ `;
+ RecTypeDup1|Error err = parseString(xmlStr);
+ test:assertTrue(err is Error);
+ test:assertEquals(( err).message(), "duplicate field 'name'");
+
+ xml xmlVal = xml `
+
+ Kanth
+
+ `;
+ RecTypeDup1|Error err2 = parseAsType(xmlVal);
+ test:assertTrue(err2 is Error);
+ test:assertEquals(( err2).message(), "duplicate field 'name'");
+
+ string xmlStr2 = string `
+
+ Kanth
+
+ `;
+ RecTypeDup2|Error err3 = parseString(xmlStr2);
+ test:assertTrue(err3 is Error);
+ test:assertEquals(( err3).message(), "duplicate field 'name'");
+
+ xml xmlVal2 = xml `
+
+ Kanth
+
+ `;
+ RecTypeDup2|Error err4 = parseAsType(xmlVal2);
+ test:assertTrue(err4 is Error);
+ test:assertEquals(( err4).message(), "duplicate field 'name'");
+}
diff --git a/ballerina/tests/toXml_test.bal b/ballerina/tests/toXml_test.bal
index e48ee94..9dc91e9 100644
--- a/ballerina/tests/toXml_test.bal
+++ b/ballerina/tests/toXml_test.bal
@@ -1191,7 +1191,7 @@ type Soap1 record {
};
@test:Config {
- groups: ["toXml", "testFail"]
+ groups: ["toXml"]
}
isolated function testXmlToRecordWithNamespaceAttachedToFields() returns error? {
Soap1 val = {
diff --git a/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/Constants.java b/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/Constants.java
index d630676..b6c330e 100644
--- a/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/Constants.java
+++ b/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/Constants.java
@@ -13,6 +13,7 @@ public class Constants {
static final String TO_XML = "toXml";
static final String NAME = "Name";
static final String NAMESPACE = "Namespace";
+ static final String ATTRIBUTE = "Attribute";
static final String XMLDATA = "xmldata";
static final String BALLERINA = "ballerina";
static final String DATA_XMLDATA = "data.xmldata";
diff --git a/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/XmldataRecordFieldValidator.java b/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/XmldataRecordFieldValidator.java
index bea7ac4..170ed26 100644
--- a/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/XmldataRecordFieldValidator.java
+++ b/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/XmldataRecordFieldValidator.java
@@ -83,7 +83,7 @@ public void perform(SyntaxNodeAnalysisContext ctx) {
boolean erroneousCompilation = diagnostics.stream()
.anyMatch(d -> d.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR));
if (erroneousCompilation) {
- rest();
+ reset();
return;
}
@@ -99,10 +99,10 @@ public void perform(SyntaxNodeAnalysisContext ctx) {
}
}
- rest();
+ reset();
}
- private void rest() {
+ private void reset() {
semanticModel = null;
allDiagnosticInfo.clear();
modulePrefix = Constants.XMLDATA;
@@ -376,6 +376,7 @@ private QualifiedName getQNameFromAnnotation(String fieldName,
String uri = "";
String name = fieldName;
String prefix = "";
+ boolean isAttribute = false;
for (AnnotationAttachmentSymbol annotAttSymbol : annotationAttachments) {
AnnotationSymbol annotation = annotAttSymbol.typeDescriptor();
if (!getAnnotModuleName(annotation).contains(Constants.XMLDATA)) {
@@ -397,9 +398,11 @@ private QualifiedName getQNameFromAnnotation(String fieldName,
}
uri = ((LinkedHashMap, ?>) annotAttSymbol.attachmentValue().orElseThrow().value())
.get("uri").toString();
+ } else if (value.equals(Constants.ATTRIBUTE)) {
+ isAttribute = true;
}
}
- return new QualifiedName(uri, name, prefix);
+ return new QualifiedName(uri, name, prefix, isAttribute);
}
private String getAnnotModuleName(AnnotationSymbol annotation) {
diff --git a/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/objects/QualifiedName.java b/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/objects/QualifiedName.java
index 7a2ab6b..f023435 100644
--- a/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/objects/QualifiedName.java
+++ b/compiler-plugin/src/main/java/io/ballerina/lib/data/xmldata/compiler/objects/QualifiedName.java
@@ -22,11 +22,13 @@ public class QualifiedName {
private final String localPart;
private final String namespaceURI;
private final String prefix;
+ private boolean isAttributeDefined;
- public QualifiedName(String namespaceURI, String localPart, String prefix) {
+ public QualifiedName(String namespaceURI, String localPart, String prefix, boolean isAttributeDefined) {
this.localPart = localPart;
this.namespaceURI = namespaceURI;
this.prefix = prefix;
+ this.isAttributeDefined = isAttributeDefined;
}
@Override
@@ -46,6 +48,6 @@ public boolean equals(Object objectToTest) {
QualifiedName qName = (QualifiedName) objectToTest;
return localPart.equals(qName.localPart) && namespaceURI.equals(qName.namespaceURI) &&
- prefix.equals(qName.prefix);
+ prefix.equals(qName.prefix) && (isAttributeDefined == qName.isAttributeDefined);
}
}
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 f9c3b95..3d26869 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
@@ -50,6 +50,10 @@
import javax.xml.namespace.QName;
+import static io.ballerina.lib.data.xmldata.xml.QualifiedName.AttributeState.ATTRIBUTE;
+import static io.ballerina.lib.data.xmldata.xml.QualifiedName.AttributeState.ELEMENT;
+import static io.ballerina.lib.data.xmldata.xml.QualifiedName.AttributeState.NOT_DEFINED;
+
/**
* A util class for the Data package's native implementation.
*
@@ -137,24 +141,29 @@ public static Map getAllFieldsInRecordType(RecordType reco
Map> fieldNames = new HashMap<>();
Map recordFields = recordType.getFields();
for (String key : recordFields.keySet()) {
+ QualifiedNameMap attributeMap = analyzerData.attributeHierarchy.peek();
QualifiedName modifiedQName =
modifiedNames.getOrDefault(key, new QualifiedName(Constants.NS_ANNOT_NOT_DEFINED, key, ""));
String localName = modifiedQName.getLocalPart();
- if (fieldMap.containsKey(modifiedQName)) {
+ if (attributeMap.contains(modifiedQName) && modifiedQName.getAttributeState() == NOT_DEFINED) {
+ if (!key.equals(attributeMap.get(modifiedQName).getFieldName())) {
+ modifiedQName.setAttributeState(ELEMENT);
+ fieldMap.put(modifiedQName, recordFields.get(key));
+ fieldNames.put(localName, new ArrayList<>(List.of(modifiedQName)));
+ }
+ } else if (fieldMap.containsKey(modifiedQName)) {
throw DiagnosticLog.error(DiagnosticErrorCode.DUPLICATE_FIELD, localName);
} else if (fieldNames.containsKey(localName)) {
- if (modifiedQName.getNamespaceURI().equals(Constants.NS_ANNOT_NOT_DEFINED)) {
- throw DiagnosticLog.error(DiagnosticErrorCode.DUPLICATE_FIELD, localName);
- }
List qNames = fieldNames.get(localName);
qNames.forEach(qName -> {
- if (qName.getNamespaceURI().equals(Constants.NS_ANNOT_NOT_DEFINED)) {
+ if (DataUtils.isSameAttributeFlag(qName.getAttributeState(), modifiedQName.getAttributeState())
+ && DataUtils.isSameNamespace(qName, modifiedQName)) {
throw DiagnosticLog.error(DiagnosticErrorCode.DUPLICATE_FIELD, localName);
}
});
fieldMap.put(modifiedQName, recordFields.get(key));
fieldNames.get(localName).add(modifiedQName);
- } else if (!analyzerData.attributeHierarchy.peek().contains(modifiedQName)) {
+ } else if (!attributeMap.contains(modifiedQName)) {
fieldMap.put(modifiedQName, recordFields.get(key));
fieldNames.put(localName, new ArrayList<>(List.of(modifiedQName)));
}
@@ -172,6 +181,7 @@ public static Map getAllAttributesInRecordType(RecordType
String attributeName = keyStr.split(Constants.FIELD_REGEX)[1].replaceAll("\\\\", "");
Map fieldAnnotation = (Map) annotations.get(annotationKey);
QualifiedName fieldQName = getFieldNameFromRecord(fieldAnnotation, attributeName);
+ fieldQName.setAttributeState(ATTRIBUTE);
fieldQName.setLocalPart(getModifiedName(fieldAnnotation, attributeName));
attributes.put(fieldQName, recordType.getFields().get(attributeName));
}
@@ -365,6 +375,17 @@ public static void logArrayMismatchErrorIfProjectionNotAllowed(boolean allowData
throw DiagnosticLog.error(DiagnosticErrorCode.ARRAY_SIZE_MISMATCH);
}
+ public static boolean isSameNamespace(QualifiedName q1, QualifiedName q2) {
+ String ns1 = q1.getNamespaceURI();
+ String ns2 = q2.getNamespaceURI();
+ return (ns1.equals(ns2) && q1.getPrefix().equals(q2.getPrefix()))
+ || ns1.equals(Constants.NS_ANNOT_NOT_DEFINED) || ns2.equals(Constants.NS_ANNOT_NOT_DEFINED);
+ }
+
+ public static boolean isSameAttributeFlag(QualifiedName.AttributeState flag1, QualifiedName.AttributeState flag2) {
+ return flag1 == NOT_DEFINED || flag2 == NOT_DEFINED || flag1.equals(flag2);
+ }
+
@SuppressWarnings("unchecked")
public static Object getModifiedRecord(BMap input, BString textFieldName, BTypedesc type) {
Type describingType = type.getDescribingType();
diff --git a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedName.java b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedName.java
index 77e0dc9..198cf7d 100644
--- a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedName.java
+++ b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedName.java
@@ -27,6 +27,20 @@ public class QualifiedName {
private String localPart;
private String namespaceURI;
private String prefix;
+ private AttributeState attributeState = AttributeState.NOT_DEFINED;
+
+ public enum AttributeState {
+ ATTRIBUTE,
+ ELEMENT,
+ NOT_DEFINED
+ }
+
+ public QualifiedName(String namespaceURI, String localPart, String prefix, AttributeState attributeState) {
+ this.localPart = localPart;
+ this.namespaceURI = namespaceURI;
+ this.prefix = prefix;
+ this.attributeState = attributeState;
+ }
public QualifiedName(String namespaceURI, String localPart, String prefix) {
this.localPart = localPart;
@@ -56,9 +70,17 @@ public String getPrefix() {
return prefix;
}
+ public void setAttributeState(AttributeState attributeState) {
+ this.attributeState = attributeState;
+ }
+
+ public AttributeState getAttributeState() {
+ return this.attributeState;
+ }
+
@Override
public int hashCode() {
- return prefix.hashCode() ^ namespaceURI.hashCode() ^ localPart.hashCode();
+ return prefix.hashCode() ^ namespaceURI.hashCode() ^ localPart.hashCode() ^ attributeState.hashCode();
}
@Override
@@ -72,6 +94,6 @@ public boolean equals(Object objectToTest) {
}
return localPart.equals(qName.localPart) && namespaceURI.equals(qName.namespaceURI) &&
- prefix.equals(qName.prefix);
+ prefix.equals(qName.prefix) && attributeState.equals(qName.attributeState);
}
}
diff --git a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedNameMap.java b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedNameMap.java
index 2a69d27..91e05c6 100644
--- a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedNameMap.java
+++ b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedNameMap.java
@@ -32,7 +32,8 @@ public V remove(QualifiedName qName) {
List qNames = fields.get(localName);
for (QualifiedName qualifiedName : fields.get(localName)) {
- if (qualifiedName.getNamespaceURI().equals(Constants.NS_ANNOT_NOT_DEFINED)) {
+ if (isSameNamespace(qualifiedName, qName)
+ && isSameAttributeFlag(qualifiedName.getAttributeState(), qName.getAttributeState())) {
field = this.members.remove(qualifiedName);
qNames.remove(qualifiedName);
break;
@@ -56,13 +57,26 @@ public boolean contains(QualifiedName qName) {
return false;
}
for (QualifiedName qualifiedName : stringToQNameMap.get(localName)) {
- if (qualifiedName.getNamespaceURI().equals(Constants.NS_ANNOT_NOT_DEFINED)) {
+ if (isSameNamespace(qualifiedName, qName)
+ && isSameAttributeFlag(qualifiedName.getAttributeState(), qName.getAttributeState())) {
return true;
}
}
return false;
}
+ private boolean isSameNamespace(QualifiedName q1, QualifiedName q2) {
+ String ns1 = q1.getNamespaceURI();
+ String ns2 = q2.getNamespaceURI();
+ return (ns1.equals(ns2) && q1.getPrefix().equals(q2.getPrefix()))
+ || ns1.equals(Constants.NS_ANNOT_NOT_DEFINED) || ns2.equals(Constants.NS_ANNOT_NOT_DEFINED);
+ }
+
+ private boolean isSameAttributeFlag(QualifiedName.AttributeState flag1, QualifiedName.AttributeState flag2) {
+ return (flag1 == QualifiedName.AttributeState.NOT_DEFINED
+ || flag2 == QualifiedName.AttributeState.NOT_DEFINED) || (flag1.equals(flag2));
+ }
+
public boolean contains(String localName) {
return stringToQNameMap.containsKey(localName);
}
@@ -89,7 +103,8 @@ public V get(QualifiedName qName) {
return null;
}
for (QualifiedName qualifiedName : stringToQNameMap.get(localName)) {
- if (qualifiedName.getNamespaceURI().equals(Constants.NS_ANNOT_NOT_DEFINED)) {
+ if (isSameNamespace(qualifiedName, qName)
+ && isSameAttributeFlag(qualifiedName.getAttributeState(), qName.getAttributeState())) {
return members.get(qualifiedName);
}
}
@@ -115,7 +130,8 @@ public QualifiedName getMatchedQualifiedName(QualifiedName elementQName) {
return null;
}
for (QualifiedName qualifiedName : stringToQNameMap.get(localName)) {
- if (qualifiedName.getNamespaceURI().equals(Constants.NS_ANNOT_NOT_DEFINED)) {
+ if (isSameNamespace(qualifiedName, elementQName)
+ && isSameAttributeFlag(qualifiedName.getAttributeState(), elementQName.getAttributeState())) {
return qualifiedName;
}
}
diff --git a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/XmlParser.java b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/XmlParser.java
index 4c16820..a7e8084 100644
--- a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/XmlParser.java
+++ b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/XmlParser.java
@@ -62,6 +62,9 @@
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static javax.xml.stream.XMLStreamConstants.PROCESSING_INSTRUCTION;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
+import static io.ballerina.lib.data.xmldata.xml.QualifiedName.AttributeState.ATTRIBUTE;
+import static io.ballerina.lib.data.xmldata.xml.QualifiedName.AttributeState.ELEMENT;
+import static io.ballerina.lib.data.xmldata.xml.QualifiedName.AttributeState.NOT_DEFINED;
/**
* Convert Xml string to a ballerina record.
@@ -892,24 +895,29 @@ private Map getAllFieldsInRecordType(RecordType recordType
Map> fieldNames = new HashMap<>();
Map recordFields = recordType.getFields();
for (String key : recordFields.keySet()) {
+ QualifiedNameMap attributeMap = xmlParserData.attributeHierarchy.peek();
QualifiedName modifiedQName =
modifiedNames.getOrDefault(key, new QualifiedName(Constants.NS_ANNOT_NOT_DEFINED, key, ""));
String localName = modifiedQName.getLocalPart();
- if (fieldMap.containsKey(modifiedQName)) {
+ if (attributeMap.contains(modifiedQName) && modifiedQName.getAttributeState() == NOT_DEFINED) {
+ if (!key.equals(attributeMap.get(modifiedQName).getFieldName())) {
+ modifiedQName.setAttributeState(ELEMENT);
+ fieldMap.put(modifiedQName, recordFields.get(key));
+ fieldNames.put(localName, new ArrayList<>(List.of(modifiedQName)));
+ }
+ } else if (fieldMap.containsKey(modifiedQName)) {
throw DiagnosticLog.error(DiagnosticErrorCode.DUPLICATE_FIELD, localName);
} else if (fieldNames.containsKey(localName)) {
- if (modifiedQName.getNamespaceURI().equals(Constants.NS_ANNOT_NOT_DEFINED)) {
- throw DiagnosticLog.error(DiagnosticErrorCode.DUPLICATE_FIELD, localName);
- }
List qNames = fieldNames.get(localName);
qNames.forEach(qName -> {
- if (qName.getNamespaceURI().equals(Constants.NS_ANNOT_NOT_DEFINED)) {
+ if (DataUtils.isSameAttributeFlag(qName.getAttributeState(), modifiedQName.getAttributeState())
+ && DataUtils.isSameNamespace(qName, modifiedQName)) {
throw DiagnosticLog.error(DiagnosticErrorCode.DUPLICATE_FIELD, localName);
}
});
fieldMap.put(modifiedQName, recordFields.get(key));
fieldNames.get(localName).add(modifiedQName);
- } else if (!xmlParserData.attributeHierarchy.peek().contains(modifiedQName)) {
+ } else if (!attributeMap.contains(modifiedQName)) {
fieldMap.put(modifiedQName, recordFields.get(key));
fieldNames.put(localName, new ArrayList<>(List.of(modifiedQName)));
}
@@ -928,6 +936,7 @@ private Map getAllAttributesInRecordType(RecordType record
Map fieldAnnotation = (Map) annotations.get(annotationKey);
QualifiedName fieldQName = DataUtils.getFieldNameFromRecord(fieldAnnotation, attributeName);
fieldQName.setLocalPart(getModifiedName(fieldAnnotation, attributeName));
+ fieldQName.setAttributeState(ATTRIBUTE);
attributes.put(fieldQName, recordType.getFields().get(attributeName));
}
}
@@ -948,7 +957,8 @@ private void handleAttributes(XMLStreamReader xmlStreamReader, XmlParserData xml
for (int i = 0; i < xmlStreamReader.getAttributeCount(); i++) {
QName attributeQName = xmlStreamReader.getAttributeName(i);
QualifiedName attQName = new QualifiedName(attributeQName.getNamespaceURI(),
- xmlParserData.attributePrefix + attributeQName.getLocalPart(), attributeQName.getPrefix());
+ xmlParserData.attributePrefix + attributeQName.getLocalPart(), attributeQName.getPrefix(),
+ ATTRIBUTE);
Field field = xmlParserData.attributeHierarchy.peek().remove(attQName);
if (field == null) {
Optional f = getFieldFromFieldHierarchy(attQName, xmlParserData);
@@ -984,8 +994,7 @@ private void handleAttributesRest(XMLStreamReader xmlStreamReader, Type restType
for (int i = 0; i < xmlStreamReader.getAttributeCount(); i++) {
QName attributeQName = xmlStreamReader.getAttributeName(i);
QualifiedName attQName = new QualifiedName(attributeQName.getNamespaceURI(),
- attributeQName.getLocalPart(), attributeQName.getPrefix());
-
+ attributeQName.getLocalPart(), attributeQName.getPrefix(), ATTRIBUTE);
try {
mapNode.put(StringUtils.fromString(attQName.getLocalPart()), convertStringToRestExpType(
StringUtils.fromString(xmlStreamReader.getAttributeValue(i)), restType));
@@ -1043,7 +1052,7 @@ private void updateStacksWhenRecordAsRestType(QualifiedName elementQName, XmlPar
private QualifiedName getElementName(XMLStreamReader xmlStreamReader) {
QName qName = xmlStreamReader.getName();
- return new QualifiedName(qName.getNamespaceURI(), qName.getLocalPart(), qName.getPrefix());
+ return new QualifiedName(qName.getNamespaceURI(), qName.getLocalPart(), qName.getPrefix(), ELEMENT);
}
/**
From efe4da67d8f15b671d88b7b9179f7793c15280fb Mon Sep 17 00:00:00 2001
From: prakanth <50439067+prakanth97@users.noreply.github.com>
Date: Tue, 9 Jul 2024 11:05:49 +0530
Subject: [PATCH 3/3] Address review suggestions
---
ballerina/tests/fromXml_test.bal | 33 +++++++++++++++----
.../data/xmldata/xml/QualifiedNameMap.java | 32 +++++++-----------
2 files changed, 37 insertions(+), 28 deletions(-)
diff --git a/ballerina/tests/fromXml_test.bal b/ballerina/tests/fromXml_test.bal
index 7ae07bc..9785d5f 100644
--- a/ballerina/tests/fromXml_test.bal
+++ b/ballerina/tests/fromXml_test.bal
@@ -2812,7 +2812,7 @@ function testProjectionWithXmlAttributeForParseAsType() returns error? {
test:assertEquals(rec.A, "2");
}
-type RecType record {
+type RecType1 record {
string name;
@Name {
value: "name"
@@ -2821,6 +2821,17 @@ type RecType record {
string duplicateName;
};
+type RecType2 record {
+ record {|
+ string \#content;
+ |} name;
+ @Name {
+ value: "name"
+ }
+ @Attribute
+ string duplicateName;
+};
+
@test:Config
isolated function testElementAndAttributeInSameScopeHaveSameName() returns error? {
string xmlStr = string `
@@ -2828,18 +2839,26 @@ isolated function testElementAndAttributeInSameScopeHaveSameName() returns error
Kanth
`;
- RecType rec = check parseString(xmlStr);
- test:assertEquals(rec.name, "Kanth");
- test:assertEquals(rec.duplicateName, "Kevin");
+ 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");
xml xmlVal = xml `
Kanth
`;
- RecType rec2 = check parseAsType(xmlVal);
- test:assertEquals(rec2.name, "Kanth");
- test:assertEquals(rec2.duplicateName, "Kevin");
+ RecType1 rec21 = check parseAsType(xmlVal);
+ test:assertEquals(rec21.name, "Kanth");
+ test:assertEquals(rec21.duplicateName, "Kevin");
+
+ RecType2 rec22 = check parseAsType(xmlVal);
+ test:assertEquals(rec22.name.\#content, "Kanth");
+ test:assertEquals(rec22.duplicateName, "Kevin");
}
type RecNs3 record {|
diff --git a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedNameMap.java b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedNameMap.java
index 91e05c6..f32cc75 100644
--- a/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedNameMap.java
+++ b/native/src/main/java/io/ballerina/lib/data/xmldata/xml/QualifiedNameMap.java
@@ -1,6 +1,6 @@
package io.ballerina.lib.data.xmldata.xml;
-import io.ballerina.lib.data.xmldata.utils.Constants;
+import io.ballerina.lib.data.xmldata.utils.DataUtils;
import java.util.ArrayList;
import java.util.HashMap;
@@ -32,8 +32,9 @@ public V remove(QualifiedName qName) {
List qNames = fields.get(localName);
for (QualifiedName qualifiedName : fields.get(localName)) {
- if (isSameNamespace(qualifiedName, qName)
- && isSameAttributeFlag(qualifiedName.getAttributeState(), qName.getAttributeState())) {
+ if (DataUtils.isSameNamespace(qualifiedName, qName)
+ && DataUtils.isSameAttributeFlag(qualifiedName.getAttributeState(),
+ qName.getAttributeState())) {
field = this.members.remove(qualifiedName);
qNames.remove(qualifiedName);
break;
@@ -57,26 +58,14 @@ public boolean contains(QualifiedName qName) {
return false;
}
for (QualifiedName qualifiedName : stringToQNameMap.get(localName)) {
- if (isSameNamespace(qualifiedName, qName)
- && isSameAttributeFlag(qualifiedName.getAttributeState(), qName.getAttributeState())) {
+ if (DataUtils.isSameNamespace(qualifiedName, qName)
+ && DataUtils.isSameAttributeFlag(qualifiedName.getAttributeState(), qName.getAttributeState())) {
return true;
}
}
return false;
}
- private boolean isSameNamespace(QualifiedName q1, QualifiedName q2) {
- String ns1 = q1.getNamespaceURI();
- String ns2 = q2.getNamespaceURI();
- return (ns1.equals(ns2) && q1.getPrefix().equals(q2.getPrefix()))
- || ns1.equals(Constants.NS_ANNOT_NOT_DEFINED) || ns2.equals(Constants.NS_ANNOT_NOT_DEFINED);
- }
-
- private boolean isSameAttributeFlag(QualifiedName.AttributeState flag1, QualifiedName.AttributeState flag2) {
- return (flag1 == QualifiedName.AttributeState.NOT_DEFINED
- || flag2 == QualifiedName.AttributeState.NOT_DEFINED) || (flag1.equals(flag2));
- }
-
public boolean contains(String localName) {
return stringToQNameMap.containsKey(localName);
}
@@ -103,8 +92,8 @@ public V get(QualifiedName qName) {
return null;
}
for (QualifiedName qualifiedName : stringToQNameMap.get(localName)) {
- if (isSameNamespace(qualifiedName, qName)
- && isSameAttributeFlag(qualifiedName.getAttributeState(), qName.getAttributeState())) {
+ if (DataUtils.isSameNamespace(qualifiedName, qName)
+ && DataUtils.isSameAttributeFlag(qualifiedName.getAttributeState(), qName.getAttributeState())) {
return members.get(qualifiedName);
}
}
@@ -130,8 +119,9 @@ public QualifiedName getMatchedQualifiedName(QualifiedName elementQName) {
return null;
}
for (QualifiedName qualifiedName : stringToQNameMap.get(localName)) {
- if (isSameNamespace(qualifiedName, elementQName)
- && isSameAttributeFlag(qualifiedName.getAttributeState(), elementQName.getAttributeState())) {
+ if (DataUtils.isSameNamespace(qualifiedName, elementQName)
+ && DataUtils.isSameAttributeFlag(qualifiedName.getAttributeState(),
+ elementQName.getAttributeState())) {
return qualifiedName;
}
}