From fb3c3d4a53afb65d5bbcb835ee7f8f156ce98c2d Mon Sep 17 00:00:00 2001 From: mindula Date: Sat, 30 Mar 2024 22:14:01 +0530 Subject: [PATCH 01/13] Add new options in xml conversion --- .../XMLToRecordConverter.java | 80 +++++++++++++++---- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index 8112eb446e55..67e961e56782 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -91,8 +91,9 @@ private XMLToRecordConverter() {} private static final String XMLDATA = "xmldata"; private static final String COLON = ":"; - public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeDesc, boolean isClosed, - boolean forceFormatRecordFields) { + public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean isRecordTypeDesc, boolean isClosed, + boolean forceFormatRecordFields, String value, + boolean hasNameSpace) { Map recordToTypeDescNodes = new LinkedHashMap<>(); Map recordToAnnotationNodes = new LinkedHashMap<>(); Map recordToElementNodes = new LinkedHashMap<>(); @@ -111,7 +112,7 @@ public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeD Element rootElement = doc.getDocumentElement(); generateRecords(rootElement, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages); + recordToElementNodes, diagnosticMessages, value, false); } catch (ParserConfigurationException parserConfigurationException) { DiagnosticMessage message = DiagnosticMessage.xmlToRecordConverter100(null); diagnosticMessages.add(message); @@ -171,11 +172,18 @@ public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeD return DiagnosticUtils.getDiagnosticResponse(diagnosticMessages, response); } + public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeDesc, boolean isClosed, + boolean forceFormatRecordFields) { + return convertXMLToRecord(xmlValue, isRecordTypeDesc, isClosed, forceFormatRecordFields, null, false); + } + private static void generateRecords(Element xmlElement, boolean isClosed, Map recordToTypeDescNodes, Map recordToAnnotationsNodes, Map recordToElementNodes, - List diagnosticMessages) { + List diagnosticMessages, + String value, + boolean hasNameSpace) { Token recordKeyWord = AbstractNodeFactory.createToken(SyntaxKind.RECORD_KEYWORD); Token bodyStartDelimiter = AbstractNodeFactory.createToken(isClosed ? SyntaxKind.OPEN_BRACE_PIPE_TOKEN : SyntaxKind.OPEN_BRACE_TOKEN); @@ -183,7 +191,7 @@ private static void generateRecords(Element xmlElement, boolean isClosed, String xmlNodeName = xmlElement.getNodeName(); List recordFields = getRecordFieldsForXMLElement(xmlElement, isClosed, recordToTypeDescNodes, - recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages); + recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages, value, hasNameSpace); if (recordToTypeDescNodes.containsKey(xmlNodeName)) { RecordTypeDescriptorNode previousRecordTypeDescriptorNode = (RecordTypeDescriptorNode) recordToTypeDescNodes.get(xmlNodeName); @@ -215,7 +223,9 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole Map recordToTypeDescNodes, Map recordToAnnotationNodes, Map recordToElementNodes, - List diagnosticMessages) { + List diagnosticMessages, + String value, + boolean hasNameSpace) { List recordFields = new ArrayList<>(); String xmlNodeName = xmlElement.getNodeName(); @@ -225,12 +235,23 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole if (xmlNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { Element xmlElementNode = (Element) xmlNode; + NamedNodeMap xmlAttributesMap = xmlElement.getAttributes(); + boolean hasAttributeWithSameName = false; + for (int j = 0; j < xmlAttributesMap.getLength(); j++) { + if(xmlAttributesMap.item(j).getNodeName().equals(xmlElementNode.getNodeName())) { + hasAttributeWithSameName = true; + break; + } + } + if (hasAttributeWithSameName) { + continue; + } boolean isLeafXMLElementNode = isLeafXMLElementNode(xmlElementNode); - if (!isLeafXMLElementNode) { + if (!isLeafXMLElementNode || xmlElementNode.getAttributes().getLength() > 0) { generateRecords(xmlElementNode, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages); + recordToElementNodes, diagnosticMessages, null, hasNameSpace); } - RecordFieldNode recordField = getRecordField(xmlElementNode, false); + RecordFieldNode recordField = getRecordField(xmlElementNode, false, hasNameSpace); if (recordFields.stream().anyMatch(recField -> ((RecordFieldNode) recField).fieldName().text() .equals(recordField.fieldName().text()))) { int indexOfRecordFieldNode = IntStream.range(0, recordFields.size()) @@ -259,8 +280,24 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole xmlElement.getPrefix().equals(xmlNode.getLocalName())) { AnnotationNode xmlNSNode = getXMLNamespaceNode(xmlNode.getLocalName(), xmlNode.getNodeValue()); recordToAnnotationNodes.put(xmlNodeName, xmlNSNode); - } else { - Node recordField = getRecordField(xmlNode); + } else if (!isLeafXMLElementNode(xmlElement)) { + RecordFieldNode recordField = (RecordFieldNode) getRecordField(xmlNode); + recordFields.add(recordField); + } + } + } + if (isLeafXMLElementNode(xmlElement) && xmlElement.getAttributes().getLength() > 0) { + Token fieldType = AbstractNodeFactory.createToken(SyntaxKind.STRING_KEYWORD); + IdentifierToken fieldName = value != null ? AbstractNodeFactory.createIdentifierToken(value) : + AbstractNodeFactory.createIdentifierToken(escapeIdentifier("#content")); + Token semicolon = AbstractNodeFactory.createToken(SyntaxKind.SEMICOLON_TOKEN); + RecordFieldNode recordFieldNode = NodeFactory.createRecordFieldNode(null, null, fieldType, + fieldName, null, semicolon); + recordFields.add(recordFieldNode); + for (int j = 0; j < xmlElement.getAttributes().getLength(); j++) { + org.w3c.dom.Node xmlAttributeNode = xmlElement.getAttributes().item(j); + if (xmlAttributeNode.getNodeType() == org.w3c.dom.Node.ATTRIBUTE_NODE) { + RecordFieldNode recordField = (RecordFieldNode) getRecordField(xmlAttributeNode); recordFields.add(recordField); } } @@ -346,15 +383,16 @@ private static List updateRecordFields(Map previo return updatedRecordFields; } - private static RecordFieldNode getRecordField(Element xmlElementNode, boolean isOptionalField) { + private static RecordFieldNode getRecordField(Element xmlElementNode, boolean isOptionalField, + boolean hasNameSpace) { Token typeName; Token questionMarkToken = AbstractNodeFactory.createToken(SyntaxKind.QUESTION_MARK_TOKEN); IdentifierToken fieldName = - AbstractNodeFactory.createIdentifierToken(escapeIdentifier(xmlElementNode.getNodeName().trim())); + AbstractNodeFactory.createIdentifierToken(escapeIdentifier(xmlElementNode.getLocalName().trim())); Token optionalFieldToken = isOptionalField ? questionMarkToken : null; Token semicolonToken = AbstractNodeFactory.createToken(SyntaxKind.SEMICOLON_TOKEN); - if (isLeafXMLElementNode(xmlElementNode)) { + if (isLeafXMLElementNode(xmlElementNode) && xmlElementNode.getAttributes().getLength() == 0) { typeName = getPrimitiveTypeName(xmlElementNode.getFirstChild().getNodeValue()); } else { // At the moment all are considered as Objects here @@ -362,9 +400,19 @@ private static RecordFieldNode getRecordField(Element xmlElementNode, boolean is String type = getRecordName(elementKey); typeName = AbstractNodeFactory.createIdentifierToken(type); } + List xmlNameNode = List.of(getXMLNamespaceNode(xmlElementNode.getPrefix(), + xmlElementNode.getNamespaceURI())); + NodeList annotationNodes = NodeFactory.createNodeList(xmlNameNode); + MetadataNode metadataNode = NodeFactory.createMetadataNode(null, annotationNodes); TypeDescriptorNode fieldTypeName = NodeFactory.createBuiltinSimpleNameReferenceNode(typeName.kind(), typeName); - return NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, optionalFieldToken, - semicolonToken); + + if (!hasNameSpace) { + return NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, + optionalFieldToken,semicolonToken); + } + return xmlElementNode.getPrefix() == null ? NodeFactory.createRecordFieldNode(null, null, fieldTypeName, + fieldName, optionalFieldToken, semicolonToken) : NodeFactory.createRecordFieldNode( + metadataNode, null, fieldTypeName, fieldName, optionalFieldToken,semicolonToken); } private static Node getRecordField(org.w3c.dom.Node xmlAttributeNode) { From b439ac77fb3b8da02547b21e739f0a3b97f12732 Mon Sep 17 00:00:00 2001 From: mindula Date: Sun, 31 Mar 2024 19:03:55 +0530 Subject: [PATCH 02/13] Fix failing test cases --- .../io/ballerina/xmltorecordconverter/XMLToRecordConverter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index 67e961e56782..b454527362dd 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -281,7 +281,7 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole AnnotationNode xmlNSNode = getXMLNamespaceNode(xmlNode.getLocalName(), xmlNode.getNodeValue()); recordToAnnotationNodes.put(xmlNodeName, xmlNSNode); } else if (!isLeafXMLElementNode(xmlElement)) { - RecordFieldNode recordField = (RecordFieldNode) getRecordField(xmlNode); + Node recordField = getRecordField(xmlNode); recordFields.add(recordField); } } From 5fcb7b90f7cbbbf05b85f1d32dcd19c3f8899bd5 Mon Sep 17 00:00:00 2001 From: mindula Date: Tue, 2 Apr 2024 10:52:39 +0530 Subject: [PATCH 03/13] Avoid adding namespaces as fields --- .../xmltorecordconverter/XMLToRecordConverter.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index b454527362dd..38649c25bf5f 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -182,8 +182,7 @@ private static void generateRecords(Element xmlElement, boolean isClosed, Map recordToAnnotationsNodes, Map recordToElementNodes, List diagnosticMessages, - String value, - boolean hasNameSpace) { + String value, boolean hasNameSpace) { Token recordKeyWord = AbstractNodeFactory.createToken(SyntaxKind.RECORD_KEYWORD); Token bodyStartDelimiter = AbstractNodeFactory.createToken(isClosed ? SyntaxKind.OPEN_BRACE_PIPE_TOKEN : SyntaxKind.OPEN_BRACE_TOKEN); @@ -224,8 +223,7 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole Map recordToAnnotationNodes, Map recordToElementNodes, List diagnosticMessages, - String value, - boolean hasNameSpace) { + String value, boolean hasNameSpace) { List recordFields = new ArrayList<>(); String xmlNodeName = xmlElement.getNodeName(); @@ -277,10 +275,10 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole if (xmlElement.getPrefix() != null && xmlNode.getPrefix() != null && xmlNode.getPrefix().equals(XMLNS_PREFIX) && - xmlElement.getPrefix().equals(xmlNode.getLocalName())) { + xmlElement.getPrefix().equals(xmlNode.getLocalName()) && hasNameSpace) { AnnotationNode xmlNSNode = getXMLNamespaceNode(xmlNode.getLocalName(), xmlNode.getNodeValue()); recordToAnnotationNodes.put(xmlNodeName, xmlNSNode); - } else if (!isLeafXMLElementNode(xmlElement)) { + } else if (!isLeafXMLElementNode(xmlElement) && !XMLNS_PREFIX.equals(xmlNode.getPrefix())) { Node recordField = getRecordField(xmlNode); recordFields.add(recordField); } From 866f8304dd7b22a5b75d435ed26d0e22c8b1d0bc Mon Sep 17 00:00:00 2001 From: mindula Date: Tue, 2 Apr 2024 10:52:55 +0530 Subject: [PATCH 04/13] Fix checkstyle failure --- .../xmltorecordconverter/XMLToRecordConverter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index 38649c25bf5f..c69746f6057a 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -286,8 +286,8 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole } if (isLeafXMLElementNode(xmlElement) && xmlElement.getAttributes().getLength() > 0) { Token fieldType = AbstractNodeFactory.createToken(SyntaxKind.STRING_KEYWORD); - IdentifierToken fieldName = value != null ? AbstractNodeFactory.createIdentifierToken(value) : - AbstractNodeFactory.createIdentifierToken(escapeIdentifier("#content")); + IdentifierToken fieldName = AbstractNodeFactory.createIdentifierToken(value == null ? + escapeIdentifier("#content") : value); Token semicolon = AbstractNodeFactory.createToken(SyntaxKind.SEMICOLON_TOKEN); RecordFieldNode recordFieldNode = NodeFactory.createRecordFieldNode(null, null, fieldType, fieldName, null, semicolon); @@ -405,8 +405,8 @@ private static RecordFieldNode getRecordField(Element xmlElementNode, boolean is TypeDescriptorNode fieldTypeName = NodeFactory.createBuiltinSimpleNameReferenceNode(typeName.kind(), typeName); if (!hasNameSpace) { - return NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, - optionalFieldToken,semicolonToken); + return NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, optionalFieldToken, + semicolonToken); } return xmlElementNode.getPrefix() == null ? NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, optionalFieldToken, semicolonToken) : NodeFactory.createRecordFieldNode( From 94c51a48e70dbf00a60369182c222655061a09cb Mon Sep 17 00:00:00 2001 From: mindula Date: Tue, 2 Apr 2024 14:03:01 +0530 Subject: [PATCH 05/13] Fix failing tests --- .../XMLToRecordConverter.java | 4 +- .../XMLToRecordConverterTests.java | 24 +++--- .../test/resources/ballerina/sample_14.bal | 16 ++-- .../test/resources/ballerina/sample_15.bal | 32 ++++++-- .../test/resources/ballerina/sample_16.bal | 82 ++++++++++++++----- .../src/test/resources/ballerina/sample_3.bal | 2 - .../src/test/resources/ballerina/sample_5.bal | 2 - .../src/test/resources/ballerina/sample_6.bal | 2 - .../src/test/resources/ballerina/sample_8.bal | 54 ++++++++++-- .../src/test/resources/ballerina/sample_9.bal | 60 ++++++++++---- 10 files changed, 197 insertions(+), 81 deletions(-) diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index c69746f6057a..91e87eed4efe 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -112,7 +112,7 @@ public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean is Element rootElement = doc.getDocumentElement(); generateRecords(rootElement, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages, value, false); + recordToElementNodes, diagnosticMessages, value, hasNameSpace); } catch (ParserConfigurationException parserConfigurationException) { DiagnosticMessage message = DiagnosticMessage.xmlToRecordConverter100(null); diagnosticMessages.add(message); @@ -417,7 +417,7 @@ private static Node getRecordField(org.w3c.dom.Node xmlAttributeNode) { Token typeName = AbstractNodeFactory.createToken(SyntaxKind.STRING_KEYWORD);; TypeDescriptorNode fieldTypeName = NodeFactory.createBuiltinSimpleNameReferenceNode(typeName.kind(), typeName); IdentifierToken fieldName = - AbstractNodeFactory.createIdentifierToken(escapeIdentifier(xmlAttributeNode.getNodeName())); + AbstractNodeFactory.createIdentifierToken(escapeIdentifier(xmlAttributeNode.getLocalName())); Token equalToken = AbstractNodeFactory.createToken(SyntaxKind.EQUAL_TOKEN); Token semicolonToken = AbstractNodeFactory.createToken(SyntaxKind.SEMICOLON_TOKEN); NodeList annotations = AbstractNodeFactory.createNodeList(getXMLAttributeNode()); diff --git a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java index c4a9953f86ed..967e715c2ba1 100644 --- a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java +++ b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java @@ -157,8 +157,8 @@ public void testBasicXMLWithTwoLevelsWithDifferentElements() throws IOException @Test(description = "testBasicXMLWithNodesWithSameName") public void testBasicXMLWithNodesWithSameName() throws IOException { String xmlFileContent = Files.readString(sample3XML); - String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) - .getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( + xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample3Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -202,8 +202,8 @@ public void testBasicXMLWithMultipleLevelsOfNodes() throws IOException { @Test(description = "testBasicXMLWithNamespace") public void testBasicXMLWithNamespace() throws IOException { String xmlFileContent = Files.readString(sample8XML); - String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) - .getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( + xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample8Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -211,8 +211,8 @@ public void testBasicXMLWithNamespace() throws IOException { @Test(description = "testComplexXMLWithNamespace") public void testComplexXMLWithNamespace() throws IOException { String xmlFileContent = Files.readString(sample9XML); - String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) - .getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( + xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample9Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -256,8 +256,8 @@ public void testXMLWithOptionalFieldsInMultipleNestedNodes() throws IOException @Test(description = "testXMLWithMultipleNamespaces") public void testXMLWithMultipleNamespaces() throws IOException { String xmlFileContent = Files.readString(sample14XML); - String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) - .getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( + xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample14Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -265,8 +265,8 @@ public void testXMLWithMultipleNamespaces() throws IOException { @Test(description = "testComplexXMLWithMultipleNamespaces") public void testComplexXMLWithMultipleNamespaces() throws IOException { String xmlFileContent = Files.readString(sample15XML); - String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) - .getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( + xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample15Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -274,8 +274,8 @@ public void testComplexXMLWithMultipleNamespaces() throws IOException { @Test(description = "testComplexXMLWithMultipleNamespacesAndRecurringNodes") public void testComplexXMLWithMultipleNamespacesAndRecurringNodes() throws IOException { String xmlFileContent = Files.readString(sample16XML); - String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) - .getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( + xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample16Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_14.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_14.bal index f58a65e3cbaf..66870fdbb402 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_14.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_14.bal @@ -1,5 +1,9 @@ type Main_MainElement record { - string[] child\:childElement; + @xmldata:Namespace { + prefix: "child", + uri:"http://example.com/child" + } + string[] childElement; }; @xmldata:Name { @@ -10,9 +14,9 @@ prefix: "root", uri: "http://example.com/root" } type Root_Root record { - Main_MainElement main\:mainElement; - @xmldata:Attribute - string xmlns\:child = "http://example.com/child"; - @xmldata:Attribute - string xmlns\:main = "http://example.com/main"; + @xmldata:Namespace { + prefix: "main", + uri: "http://example.com/main" + } + Main_MainElement mainElement; }; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_15.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_15.bal index ac6fef0cedd1..0e259d280855 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_15.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_15.bal @@ -1,11 +1,27 @@ type Main_Location record { - string main\:city; - string main\:state; + @xmldata:Namespace { + prefix: "main", + uri: "http://example.com/main" + } + string city; + @xmldata:Namespace { + prefix: "main", + uri: "http://example.com/main" + } + string state; }; type Main_CompanyInfo record { - string main\:name; - Main_Location main\:location; + @xmldata:Namespace { + prefix: "main", + uri: "http://example.com/main" + } + string name; + @xmldata:Namespace { + prefix: "main", + uri: "http://example.com/main" + } + Main_Location location; }; type Project record { @@ -47,11 +63,13 @@ type Mixed record { uri: "http://example.com/root" } type Root_Root record { - Main_CompanyInfo main\:companyInfo; + @xmldata:Namespace { + prefix: "main", + uri: "http://example.com/main" + } + Main_CompanyInfo companyInfo; Employees employees; Mixed mixed; @xmldata:Attribute string version; - @xmldata:Attribute - string xmlns\:main = "http://example.com/main"; }; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_16.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_16.bal index 44dac20e57cc..d13bd07e5cdc 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_16.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_16.bal @@ -1,39 +1,77 @@ type C_Course record { - string u\:name; - int c\:intake?; - string p\:professor?; + @xmldata:Namespace { + prefix: "u", + uri: "http://example.com/university" + } + string name; + @xmldata:Namespace { + prefix: "c", + uri: "http://example.com/course" + } + int intake?; + @xmldata:Namespace { + prefix: "p", + uri: "http://example.com/professor" + } + string professor?; }; type D_SubDepartment record { - string d\:name; - C_Course[] c\:course?; - D_SubDepartment[] d\:subDepartment?; + @xmldata:Namespace { + prefix: "d", + uri: "http://example.com/department" + } + string name; + @xmldata:Namespace { + prefix: "c", + uri: "http://example.com/course" + } + C_Course[] course?; + @xmldata:Namespace { + prefix: "d", + uri: "http://example.com/department" + } + D_SubDepartment[] subDepartment?; }; type D_Department record { - string u\:name; - C_Course[] c\:course; - D_SubDepartment d\:subDepartment?; + @xmldata:Namespace { + prefix: "u", + uri: "http://example.com/university" + } + string name; + @xmldata:Namespace { + prefix: "c", + uri: "http://example.com/course" + } + C_Course[] course; + @xmldata:Namespace { + prefix: "d", + uri: "http://example.com/department" + } + D_SubDepartment subDepartment?; }; type F_Faculty record { - string u\:name; - D_Department[] d\:department; + @xmldata:Namespace { + prefix: "u", + uri: "http://example.com/university" + } + string name; + @xmldata:Namespace { + prefix: "d", + uri: "http://example.com/department" + } + D_Department[] department; }; @xmldata:Name { value: "university" } type University record { - F_Faculty[] f\:faculty; - @xmldata:Attribute - string xmlns\:c = "http://example.com/course"; - @xmldata:Attribute - string xmlns\:d = "http://example.com/department"; - @xmldata:Attribute - string xmlns\:f = "http://example.com/faculty"; - @xmldata:Attribute - string xmlns\:p = "http://example.com/professor"; - @xmldata:Attribute - string xmlns\:u = "http://example.com/university"; + @xmldata:Namespace { + prefix: "f", + uri: "http://example.com/faculty" + } + F_Faculty[] faculty; }; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_3.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_3.bal index 7b3dcf0e4b59..4c29bb5ec0d4 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_3.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_3.bal @@ -19,6 +19,4 @@ type Bookstore record { Codes codes; @xmldata:Attribute string status; - @xmldata:Attribute - string xmlns\:ns0 = "http://sample.com/test"; }; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_5.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_5.bal index 3988e9033f45..e83c4a80ccf5 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_5.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_5.bal @@ -12,6 +12,4 @@ type Bookstore record { Codes codes; @xmldata:Attribute string status; - @xmldata:Attribute - string xmlns\:ns0 = "http://sample.com/test"; }; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_6.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_6.bal index 4ad5425f2ef4..218911eeee37 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_6.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_6.bal @@ -21,6 +21,4 @@ type Bookstore record { Codes codes; @xmldata:Attribute string status; - @xmldata:Attribute - string xmlns\:ns0 = "http://sample.com/test"; }; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_8.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_8.bal index b7cb7d0100e1..61a7c1cb0e3e 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_8.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_8.bal @@ -1,11 +1,27 @@ type Ns0_Address record { - string ns0\:street; - string ns0\:city; - string ns0\:country; + @xmldata:Namespace { + prefix: "ns0", + uri: "http://sample.com/test" + } + string street; + @xmldata:Namespace { + prefix: "ns0", + uri: "http://sample.com/test" + } + string city; + @xmldata:Namespace { + prefix: "ns0", + uri: "http://sample.com/test" + } + string country; }; type Ns0_Codes record { - int[] ns0\:code; + @xmldata:Namespace { + prefix: "ns0", + uri: "http://sample.com/test" + } + int[] code; }; @xmldata:Name { @@ -16,11 +32,31 @@ type Ns0_Codes record { uri: "http://sample.com/test" } type Ns0_BookStore record { - string ns0\:storeName; - int ns0\:postalCode; - boolean ns0\:isOpen; - Ns0_Address ns0\:address; - Ns0_Codes ns0\:codes; + @xmldata:Namespace { + prefix: "ns0", + uri: "http://sample.com/test" + } + string storeName; + @xmldata:Namespace { + prefix: "ns0", + uri: "http://sample.com/test" + } + int postalCode; + @xmldata:Namespace { + prefix: "ns0", + uri: "http://sample.com/test" + } + boolean isOpen; + @xmldata:Namespace { + prefix: "ns0", + uri: "http://sample.com/test" + } + Ns0_Address address; + @xmldata:Namespace { + prefix: "ns0", + uri: "http://sample.com/test" + } + Ns0_Codes codes; @xmldata:Attribute string status; }; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_9.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_9.bal index 47f51990eaa6..a8c4d8e39f20 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_9.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_9.bal @@ -1,37 +1,63 @@ type Ns1_Element1 record { @xmldata:Attribute - string ns1\:attribute1; + string attribute1; @xmldata:Attribute - string ns2\:attribute2; + string attribute2; }; type Ns2_Null record { @xmldata:Attribute - string xmlns\:xsi = "http://www.w3.org/2001/XMLSchema-instance"; - @xmldata:Attribute - string xsi\:nil; + string nil; }; type Ns2_Array record { - string[] ns2\:item; + @xmldata:Namespace { + prefix: "ns2", + uri: "http://namespace2.com" + } + string[] item; }; type Ns2_Element2 record { - string ns2\:subelement; - decimal ns2\:number; - boolean ns2\:boolean; - Ns2_Null ns2\:null; - Ns2_Array ns2\:array; + @xmldata:Namespace { + prefix: "ns2", + uri: "http://namespace2.com" + } + string subelement; + @xmldata:Namespace { + prefix: "ns2", + uri: "http://namespace2.com" + } + decimal number; + @xmldata:Namespace { + prefix: "ns2", + uri: "http://namespace2.com" + } + boolean 'boolean; + @xmldata:Namespace { + prefix: "ns2", + uri: "http://namespace2.com" + } + Ns2_Null 'null; + @xmldata:Namespace { + prefix: "ns2", + uri: "http://namespace2.com" + } + Ns2_Array array; }; @xmldata:Name { value: "root" } type Root record { - Ns1_Element1 ns1\:element1; - Ns2_Element2 ns2\:element2; - @xmldata:Attribute - string xmlns\:ns1 = "http://namespace1.com"; - @xmldata:Attribute - string xmlns\:ns2 = "http://namespace2.com"; + @xmldata:Namespace { + prefix: "ns1", + uri: "http://namespace1.com" + } + Ns1_Element1 element1; + @xmldata:Namespace { + prefix: "ns2", + uri: "http://namespace2.com" + } + Ns2_Element2 element2; }; From 346fa4377ef4c431abd297590d32b374d07723a3 Mon Sep 17 00:00:00 2001 From: mindula Date: Tue, 2 Apr 2024 14:03:52 +0530 Subject: [PATCH 06/13] Remove unnecessary semicolons --- .../ballerina/xmltorecordconverter/XMLToRecordConverter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index 91e87eed4efe..8ffc8eb46b55 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -155,7 +155,7 @@ public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean is }).toList(); NodeList moduleMembers = - AbstractNodeFactory.createNodeList(new ArrayList<>(typeDefNodes));; + AbstractNodeFactory.createNodeList(new ArrayList<>(typeDefNodes)); Token eofToken = AbstractNodeFactory.createIdentifierToken(""); ModulePartNode modulePartNode = NodeFactory.createModulePartNode(imports, moduleMembers, eofToken); @@ -414,7 +414,7 @@ private static RecordFieldNode getRecordField(Element xmlElementNode, boolean is } private static Node getRecordField(org.w3c.dom.Node xmlAttributeNode) { - Token typeName = AbstractNodeFactory.createToken(SyntaxKind.STRING_KEYWORD);; + Token typeName = AbstractNodeFactory.createToken(SyntaxKind.STRING_KEYWORD); TypeDescriptorNode fieldTypeName = NodeFactory.createBuiltinSimpleNameReferenceNode(typeName.kind(), typeName); IdentifierToken fieldName = AbstractNodeFactory.createIdentifierToken(escapeIdentifier(xmlAttributeNode.getLocalName())); From 70045a7e5884a3ec1df7388fe3e047f44382be61 Mon Sep 17 00:00:00 2001 From: mindula Date: Tue, 2 Apr 2024 20:35:01 +0530 Subject: [PATCH 07/13] Refactor the code --- .../XMLToRecordConverter.java | 18 +++++++------- .../XMLToRecordConverterTests.java | 24 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index 8ffc8eb46b55..66b1c3fe94dd 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -93,7 +93,7 @@ private XMLToRecordConverter() {} public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean isRecordTypeDesc, boolean isClosed, boolean forceFormatRecordFields, String value, - boolean hasNameSpace) { + boolean withNameSpaces) { Map recordToTypeDescNodes = new LinkedHashMap<>(); Map recordToAnnotationNodes = new LinkedHashMap<>(); Map recordToElementNodes = new LinkedHashMap<>(); @@ -112,7 +112,7 @@ public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean is Element rootElement = doc.getDocumentElement(); generateRecords(rootElement, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages, value, hasNameSpace); + recordToElementNodes, diagnosticMessages, value, withNameSpaces); } catch (ParserConfigurationException parserConfigurationException) { DiagnosticMessage message = DiagnosticMessage.xmlToRecordConverter100(null); diagnosticMessages.add(message); @@ -174,7 +174,7 @@ public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean is public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeDesc, boolean isClosed, boolean forceFormatRecordFields) { - return convertXMLToRecord(xmlValue, isRecordTypeDesc, isClosed, forceFormatRecordFields, null, false); + return convertXMLToRecord(xmlValue, isRecordTypeDesc, isClosed, forceFormatRecordFields, null, true); } private static void generateRecords(Element xmlElement, boolean isClosed, @@ -182,7 +182,7 @@ private static void generateRecords(Element xmlElement, boolean isClosed, Map recordToAnnotationsNodes, Map recordToElementNodes, List diagnosticMessages, - String value, boolean hasNameSpace) { + String value, boolean withNameSpace) { Token recordKeyWord = AbstractNodeFactory.createToken(SyntaxKind.RECORD_KEYWORD); Token bodyStartDelimiter = AbstractNodeFactory.createToken(isClosed ? SyntaxKind.OPEN_BRACE_PIPE_TOKEN : SyntaxKind.OPEN_BRACE_TOKEN); @@ -190,7 +190,7 @@ private static void generateRecords(Element xmlElement, boolean isClosed, String xmlNodeName = xmlElement.getNodeName(); List recordFields = getRecordFieldsForXMLElement(xmlElement, isClosed, recordToTypeDescNodes, - recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages, value, hasNameSpace); + recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages, value, withNameSpace); if (recordToTypeDescNodes.containsKey(xmlNodeName)) { RecordTypeDescriptorNode previousRecordTypeDescriptorNode = (RecordTypeDescriptorNode) recordToTypeDescNodes.get(xmlNodeName); @@ -223,7 +223,7 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole Map recordToAnnotationNodes, Map recordToElementNodes, List diagnosticMessages, - String value, boolean hasNameSpace) { + String value, boolean withNameSpace) { List recordFields = new ArrayList<>(); String xmlNodeName = xmlElement.getNodeName(); @@ -247,9 +247,9 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole boolean isLeafXMLElementNode = isLeafXMLElementNode(xmlElementNode); if (!isLeafXMLElementNode || xmlElementNode.getAttributes().getLength() > 0) { generateRecords(xmlElementNode, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages, null, hasNameSpace); + recordToElementNodes, diagnosticMessages, null, withNameSpace); } - RecordFieldNode recordField = getRecordField(xmlElementNode, false, hasNameSpace); + RecordFieldNode recordField = getRecordField(xmlElementNode, false, withNameSpace); if (recordFields.stream().anyMatch(recField -> ((RecordFieldNode) recField).fieldName().text() .equals(recordField.fieldName().text()))) { int indexOfRecordFieldNode = IntStream.range(0, recordFields.size()) @@ -275,7 +275,7 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole if (xmlElement.getPrefix() != null && xmlNode.getPrefix() != null && xmlNode.getPrefix().equals(XMLNS_PREFIX) && - xmlElement.getPrefix().equals(xmlNode.getLocalName()) && hasNameSpace) { + xmlElement.getPrefix().equals(xmlNode.getLocalName()) && withNameSpace) { AnnotationNode xmlNSNode = getXMLNamespaceNode(xmlNode.getLocalName(), xmlNode.getNodeValue()); recordToAnnotationNodes.put(xmlNodeName, xmlNSNode); } else if (!isLeafXMLElementNode(xmlElement) && !XMLNS_PREFIX.equals(xmlNode.getPrefix())) { diff --git a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java index 967e715c2ba1..c4a9953f86ed 100644 --- a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java +++ b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java @@ -157,8 +157,8 @@ public void testBasicXMLWithTwoLevelsWithDifferentElements() throws IOException @Test(description = "testBasicXMLWithNodesWithSameName") public void testBasicXMLWithNodesWithSameName() throws IOException { String xmlFileContent = Files.readString(sample3XML); - String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( - xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) + .getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample3Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -202,8 +202,8 @@ public void testBasicXMLWithMultipleLevelsOfNodes() throws IOException { @Test(description = "testBasicXMLWithNamespace") public void testBasicXMLWithNamespace() throws IOException { String xmlFileContent = Files.readString(sample8XML); - String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( - xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) + .getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample8Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -211,8 +211,8 @@ public void testBasicXMLWithNamespace() throws IOException { @Test(description = "testComplexXMLWithNamespace") public void testComplexXMLWithNamespace() throws IOException { String xmlFileContent = Files.readString(sample9XML); - String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( - xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) + .getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample9Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -256,8 +256,8 @@ public void testXMLWithOptionalFieldsInMultipleNestedNodes() throws IOException @Test(description = "testXMLWithMultipleNamespaces") public void testXMLWithMultipleNamespaces() throws IOException { String xmlFileContent = Files.readString(sample14XML); - String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( - xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) + .getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample14Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -265,8 +265,8 @@ public void testXMLWithMultipleNamespaces() throws IOException { @Test(description = "testComplexXMLWithMultipleNamespaces") public void testComplexXMLWithMultipleNamespaces() throws IOException { String xmlFileContent = Files.readString(sample15XML); - String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( - xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) + .getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample15Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } @@ -274,8 +274,8 @@ public void testComplexXMLWithMultipleNamespaces() throws IOException { @Test(description = "testComplexXMLWithMultipleNamespacesAndRecurringNodes") public void testComplexXMLWithMultipleNamespacesAndRecurringNodes() throws IOException { String xmlFileContent = Files.readString(sample16XML); - String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord( - xmlFileContent, false, false, false, null, true).getCodeBlock().replaceAll("\\s+", ""); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) + .getCodeBlock().replaceAll("\\s+", ""); String expectedCodeBlock = Files.readString(sample16Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } From efbb4c8c65f51aba58b1782887a2adb326c172b6 Mon Sep 17 00:00:00 2001 From: mindula Date: Tue, 2 Apr 2024 20:56:28 +0530 Subject: [PATCH 08/13] Address review suggestions --- .../XMLToRecordConverter.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index 66b1c3fe94dd..22dc17036929 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -61,9 +61,11 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -228,20 +230,17 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole String xmlNodeName = xmlElement.getNodeName(); org.w3c.dom.NodeList xmlNodeList = xmlElement.getChildNodes(); + NamedNodeMap xmlAttributesMap = xmlElement.getAttributes(); + Set attributeNames = new HashSet<>(); + for (int j = 0; j < xmlAttributesMap.getLength(); j++) { + attributeNames.add(xmlAttributesMap.item(j).getNodeName()); + } for (int i = 0; i < xmlNodeList.getLength(); i++) { org.w3c.dom.Node xmlNode = xmlNodeList.item(i); if (xmlNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { Element xmlElementNode = (Element) xmlNode; - NamedNodeMap xmlAttributesMap = xmlElement.getAttributes(); - boolean hasAttributeWithSameName = false; - for (int j = 0; j < xmlAttributesMap.getLength(); j++) { - if(xmlAttributesMap.item(j).getNodeName().equals(xmlElementNode.getNodeName())) { - hasAttributeWithSameName = true; - break; - } - } - if (hasAttributeWithSameName) { + if (attributeNames.contains(xmlElementNode.getNodeName())) { continue; } boolean isLeafXMLElementNode = isLeafXMLElementNode(xmlElementNode); @@ -268,7 +267,6 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole } } } - NamedNodeMap xmlAttributesMap = xmlElement.getAttributes(); for (int i = 0; i < xmlAttributesMap.getLength(); i++) { org.w3c.dom.Node xmlNode = xmlAttributesMap.item(i); if (xmlNode.getNodeType() == org.w3c.dom.Node.ATTRIBUTE_NODE) { @@ -410,7 +408,7 @@ private static RecordFieldNode getRecordField(Element xmlElementNode, boolean is } return xmlElementNode.getPrefix() == null ? NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, optionalFieldToken, semicolonToken) : NodeFactory.createRecordFieldNode( - metadataNode, null, fieldTypeName, fieldName, optionalFieldToken,semicolonToken); + metadataNode, null, fieldTypeName, fieldName, optionalFieldToken, semicolonToken); } private static Node getRecordField(org.w3c.dom.Node xmlAttributeNode) { From c79c80ff72c20ec271e34795a42f667153a19bef Mon Sep 17 00:00:00 2001 From: mindula Date: Wed, 3 Apr 2024 09:39:42 +0530 Subject: [PATCH 09/13] Add tests --- .../XMLToRecordConverter.java | 2 +- .../XMLToRecordConverterTests.java | 70 ++++++++++++++++ .../test/resources/ballerina/sample_17.bal | 15 ++++ .../test/resources/ballerina/sample_18.bal | 21 +++++ .../test/resources/ballerina/sample_19.bal | 22 +++++ .../test/resources/ballerina/sample_20.bal | 45 ++++++++++ .../test/resources/ballerina/sample_21.bal | 83 +++++++++++++++++++ .../src/test/resources/xml/sample_17.xml | 9 ++ .../src/test/resources/xml/sample_18.xml | 9 ++ .../src/test/resources/xml/sample_19.xml | 18 ++++ .../src/test/resources/xml/sample_20.xml | 10 +++ .../src/test/resources/xml/sample_21.xml | 15 ++++ 12 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 misc/xml-to-record-converter/src/test/resources/ballerina/sample_17.bal create mode 100644 misc/xml-to-record-converter/src/test/resources/ballerina/sample_18.bal create mode 100644 misc/xml-to-record-converter/src/test/resources/ballerina/sample_19.bal create mode 100644 misc/xml-to-record-converter/src/test/resources/ballerina/sample_20.bal create mode 100644 misc/xml-to-record-converter/src/test/resources/ballerina/sample_21.bal create mode 100644 misc/xml-to-record-converter/src/test/resources/xml/sample_17.xml create mode 100644 misc/xml-to-record-converter/src/test/resources/xml/sample_18.xml create mode 100644 misc/xml-to-record-converter/src/test/resources/xml/sample_19.xml create mode 100644 misc/xml-to-record-converter/src/test/resources/xml/sample_20.xml create mode 100644 misc/xml-to-record-converter/src/test/resources/xml/sample_21.xml diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index 22dc17036929..1e220af30506 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -246,7 +246,7 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole boolean isLeafXMLElementNode = isLeafXMLElementNode(xmlElementNode); if (!isLeafXMLElementNode || xmlElementNode.getAttributes().getLength() > 0) { generateRecords(xmlElementNode, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages, null, withNameSpace); + recordToElementNodes, diagnosticMessages, value, withNameSpace); } RecordFieldNode recordField = getRecordField(xmlElementNode, false, withNameSpace); if (recordFields.stream().anyMatch(recField -> ((RecordFieldNode) recField).fieldName().text() diff --git a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java index c4a9953f86ed..90c8b00d9cc4 100644 --- a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java +++ b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java @@ -124,6 +124,31 @@ public class XMLToRecordConverterTests { private final Path sample16Bal = RES_DIR.resolve(BAL_DIR) .resolve("sample_16.bal"); + private final Path sample17XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_17.xml"); + private final Path sample17Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_17.bal"); + + private final Path sample18XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_18.xml"); + private final Path sample18Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_18.bal"); + + private final Path sample19XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_19.xml"); + private final Path sample19Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_19.bal"); + + private final Path sample20XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_20.xml"); + private final Path sample20Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_20.bal"); + + private final Path sample21XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_21.xml"); + private final Path sample21Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_21.bal"); + private static final String XMLToRecordServiceEP = "xmlToRecord/convert"; @@ -280,6 +305,51 @@ public void testComplexXMLWithMultipleNamespacesAndRecurringNodes() throws IOExc Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } + @Test(description = "testWithAttribute") + public void testWithAttribute() throws IOException { + String xmlFileContent = Files.readString(sample17XML); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) + .getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample17Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + + @Test(description = "testWithMultipleAttributes") + public void testWithMultipleAttributes() throws IOException { + String xmlFileContent = Files.readString(sample18XML); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false) + .getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample18Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + + @Test(description = "testXMLWithNamespacesWithoutNamespaceAnnotation") + public void testXMLWithNamespacesWithoutNamespaceAttribute() throws IOException { + String xmlFileContent = Files.readString(sample19XML); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord(xmlFileContent, false, false, false, + "amount", false).getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample19Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + + @Test(description = "testXMLWithMultipleAttributesAndNamespacesWithoutAnnotations") + public void testXMLWithMultipleAttributesAndNamespacesWithoutAnnotations() throws IOException { + String xmlFileContent = Files.readString(sample20XML); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord(xmlFileContent, false, false, false, + null, false).getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample20Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + + @Test(description = "testXMLWithMultipleAttributesAndNamespacesWithAnnotations") + public void testXMLWithMultipleAttributesAndNamespacesWithAnnotations() throws IOException { + String xmlFileContent = Files.readString(sample21XML); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord(xmlFileContent, false, false, false, + null, true).getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample21Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + @Test(description = "testXMLToRecordService") public void testXMLToRecordService() throws IOException, ExecutionException, InterruptedException { Endpoint serviceEndpoint = TestUtil.initializeLanguageSever(); diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_17.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_17.bal new file mode 100644 index 000000000000..5757470f6980 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_17.bal @@ -0,0 +1,15 @@ +type Title record { + string \#content; + @xmldata:Attribute + string lang; +}; + +@xmldata:Name {value: "book"} +type Book record { + string author; + Title title; + string genre; + decimal price; + string publish_date; + string description; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_18.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_18.bal new file mode 100644 index 000000000000..a69e86e49450 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_18.bal @@ -0,0 +1,21 @@ +type Title record { + string \#content; + @xmldata:Attribute + string lang; +}; + +type Genre record { + string \#content; + @xmldata:Attribute + string category; +}; + +@xmldata:Name {value: "book"} +type Book record { + string author; + Title title; + Genre genre; + decimal price; + string publish_date; + string description; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_19.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_19.bal new file mode 100644 index 000000000000..3e974014596f --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_19.bal @@ -0,0 +1,22 @@ +type Book_Author record { + string name; + string country; +}; + +type Meta_Reviews record { + string[] review; +}; + +type Book_Book record { + string title; + Book_Author author; + string genre; + string publication_date; + decimal rating; + Meta_Reviews reviews; +}; + +@xmldata:Name {value: "library"} +type Library record { + Book_Book book; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_20.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_20.bal new file mode 100644 index 000000000000..487e0af8daf8 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_20.bal @@ -0,0 +1,45 @@ +type Book_Title record { + string \#content; + @xmldata:Attribute + string edition; + @xmldata:Attribute + string lang; +}; + +type Book_Author record { + string \#content; + @xmldata:Attribute + string gender; + @xmldata:Attribute + string nationality; +}; + +type Genre_Genre record { + string \#content; + @xmldata:Attribute + string category; + @xmldata:Attribute + string 'type; +}; + +type Currency_Price record { + string \#content; + @xmldata:Attribute + string currency; + @xmldata:Attribute + string discounted; +}; + +type Book_Book record { + Book_Title title; + Book_Author author; + Genre_Genre genre; + Currency_Price price; + string publish_date; + string description; +}; + +@xmldata:Name {value: "library"} +type Library record { + Book_Book book; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_21.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_21.bal new file mode 100644 index 000000000000..0db417563944 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_21.bal @@ -0,0 +1,83 @@ +type Course_Title record { + string \#content; + @xmldata:Attribute + string lang; + @xmldata:Attribute + string level; +}; + +type Instructor_Name record { + string \#content; + @xmldata:Attribute + string gender; +}; + +type Instructor_Instructor record { + @xmldata:Namespace { + prefix: "instructor", + uri: "http://example.com/instructors" + } + Instructor_Name name; + @xmldata:Namespace { + prefix: "instructor", + uri: "http://example.com/instructors" + } + string office; +}; + +type Enrollment_Enrollment record { + @xmldata:Attribute + string capacity; + @xmldata:Attribute + string enrolled; +}; + +type Course_Course record { + @xmldata:Namespace { + prefix: "course", + uri: "http://example.com/courses" + } + string code; + @xmldata:Namespace { + prefix: "course", + uri: "http://example.com/courses" + } + Course_Title title; + @xmldata:Namespace { + prefix: "instructor", + uri: "http://example.com/instructors" + } + Instructor_Instructor instructor; + @xmldata:Namespace { + prefix: "enrollment", + uri: "http://example.com/enrollment" + } + Enrollment_Enrollment enrollment; +}; + +type Dept_Department record { + @xmldata:Namespace { + prefix: "dept", + uri: "http://example.com/departments" + } + string name; + @xmldata:Namespace { + prefix: "dept", + uri: "http://example.com/departments" + } + string location; + @xmldata:Namespace { + prefix: "course", + uri: "http://example.com/courses" + } + Course_Course course; +}; + +@xmldata:Name {value: "university"} +type University record { + @xmldata:Namespace { + prefix: "dept", + uri: "http://example.com/departments" + } + Dept_Department department; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_17.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_17.xml new file mode 100644 index 000000000000..b82a9414e6b6 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_17.xml @@ -0,0 +1,9 @@ + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications + with XML. + diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_18.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_18.xml new file mode 100644 index 000000000000..5a8a6dac68cf --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_18.xml @@ -0,0 +1,9 @@ + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications + with XML. + diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_19.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_19.xml new file mode 100644 index 000000000000..e3f72b0b786c --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_19.xml @@ -0,0 +1,18 @@ + + + Sample Book + + John Doe + USA + + Fiction + 2023-01-01 + 4.5 + + Excellent read! + Highly recommended. + + + diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_20.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_20.xml new file mode 100644 index 000000000000..3603d668c728 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_20.xml @@ -0,0 +1,10 @@ + + + XML Developer's Guide + Gambardella, Matthew + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications with XML. + + diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_21.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_21.xml new file mode 100644 index 000000000000..8bf157f4e8c1 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_21.xml @@ -0,0 +1,15 @@ + + + Computer Science + Engineering Building + + CS101 + Introduction to Computer Science + + Dr. Smith + Room 301 + + + + + From a319aeb12a5774ca9877fb33378035041320f4b1 Mon Sep 17 00:00:00 2001 From: mindula Date: Wed, 3 Apr 2024 15:11:45 +0530 Subject: [PATCH 10/13] Fix formatting --- .../test/resources/ballerina/sample_14.bal | 6 ++--- .../test/resources/ballerina/sample_15.bal | 10 ++++---- .../test/resources/ballerina/sample_16.bal | 24 +++++++++---------- .../test/resources/ballerina/sample_21.bal | 20 ++++++++-------- .../src/test/resources/ballerina/sample_8.bal | 18 +++++++------- .../src/test/resources/ballerina/sample_9.bal | 16 ++++++------- 6 files changed, 47 insertions(+), 47 deletions(-) diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_14.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_14.bal index 66870fdbb402..a9067443751d 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_14.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_14.bal @@ -1,6 +1,6 @@ type Main_MainElement record { @xmldata:Namespace { - prefix: "child", + prefix: "child", uri:"http://example.com/child" } string[] childElement; @@ -10,12 +10,12 @@ type Main_MainElement record { value: "root" } @xmldata:Namespace { -prefix: "root", + prefix: "root", uri: "http://example.com/root" } type Root_Root record { @xmldata:Namespace { - prefix: "main", + prefix: "main", uri: "http://example.com/main" } Main_MainElement mainElement; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_15.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_15.bal index 0e259d280855..4f7c7b0f7a1a 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_15.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_15.bal @@ -1,11 +1,11 @@ type Main_Location record { @xmldata:Namespace { - prefix: "main", + prefix: "main", uri: "http://example.com/main" } string city; @xmldata:Namespace { - prefix: "main", + prefix: "main", uri: "http://example.com/main" } string state; @@ -13,12 +13,12 @@ type Main_Location record { type Main_CompanyInfo record { @xmldata:Namespace { - prefix: "main", + prefix: "main", uri: "http://example.com/main" } string name; @xmldata:Namespace { - prefix: "main", + prefix: "main", uri: "http://example.com/main" } Main_Location location; @@ -64,7 +64,7 @@ type Mixed record { } type Root_Root record { @xmldata:Namespace { - prefix: "main", + prefix: "main", uri: "http://example.com/main" } Main_CompanyInfo companyInfo; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_16.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_16.bal index d13bd07e5cdc..3f3c9a4c49ba 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_16.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_16.bal @@ -1,16 +1,16 @@ type C_Course record { @xmldata:Namespace { - prefix: "u", + prefix: "u", uri: "http://example.com/university" } string name; @xmldata:Namespace { - prefix: "c", + prefix: "c", uri: "http://example.com/course" } int intake?; @xmldata:Namespace { - prefix: "p", + prefix: "p", uri: "http://example.com/professor" } string professor?; @@ -18,17 +18,17 @@ type C_Course record { type D_SubDepartment record { @xmldata:Namespace { - prefix: "d", + prefix: "d", uri: "http://example.com/department" } string name; @xmldata:Namespace { - prefix: "c", + prefix: "c", uri: "http://example.com/course" } C_Course[] course?; @xmldata:Namespace { - prefix: "d", + prefix: "d", uri: "http://example.com/department" } D_SubDepartment[] subDepartment?; @@ -36,17 +36,17 @@ type D_SubDepartment record { type D_Department record { @xmldata:Namespace { - prefix: "u", + prefix: "u", uri: "http://example.com/university" } string name; @xmldata:Namespace { - prefix: "c", + prefix: "c", uri: "http://example.com/course" } C_Course[] course; @xmldata:Namespace { - prefix: "d", + prefix: "d", uri: "http://example.com/department" } D_SubDepartment subDepartment?; @@ -54,12 +54,12 @@ type D_Department record { type F_Faculty record { @xmldata:Namespace { - prefix: "u", + prefix: "u", uri: "http://example.com/university" } string name; @xmldata:Namespace { - prefix: "d", + prefix: "d", uri: "http://example.com/department" } D_Department[] department; @@ -70,7 +70,7 @@ type F_Faculty record { } type University record { @xmldata:Namespace { - prefix: "f", + prefix: "f", uri: "http://example.com/faculty" } F_Faculty[] faculty; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_21.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_21.bal index 0db417563944..0ce77d75335f 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_21.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_21.bal @@ -14,12 +14,12 @@ type Instructor_Name record { type Instructor_Instructor record { @xmldata:Namespace { - prefix: "instructor", + prefix: "instructor", uri: "http://example.com/instructors" } Instructor_Name name; @xmldata:Namespace { - prefix: "instructor", + prefix: "instructor", uri: "http://example.com/instructors" } string office; @@ -34,22 +34,22 @@ type Enrollment_Enrollment record { type Course_Course record { @xmldata:Namespace { - prefix: "course", + prefix: "course", uri: "http://example.com/courses" } string code; @xmldata:Namespace { - prefix: "course", + prefix: "course", uri: "http://example.com/courses" } Course_Title title; @xmldata:Namespace { - prefix: "instructor", + prefix: "instructor", uri: "http://example.com/instructors" } Instructor_Instructor instructor; @xmldata:Namespace { - prefix: "enrollment", + prefix: "enrollment", uri: "http://example.com/enrollment" } Enrollment_Enrollment enrollment; @@ -57,17 +57,17 @@ type Course_Course record { type Dept_Department record { @xmldata:Namespace { - prefix: "dept", + prefix: "dept", uri: "http://example.com/departments" } string name; @xmldata:Namespace { - prefix: "dept", + prefix: "dept", uri: "http://example.com/departments" } string location; @xmldata:Namespace { - prefix: "course", + prefix: "course", uri: "http://example.com/courses" } Course_Course course; @@ -76,7 +76,7 @@ type Dept_Department record { @xmldata:Name {value: "university"} type University record { @xmldata:Namespace { - prefix: "dept", + prefix: "dept", uri: "http://example.com/departments" } Dept_Department department; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_8.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_8.bal index 61a7c1cb0e3e..998914c2830b 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_8.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_8.bal @@ -1,16 +1,16 @@ type Ns0_Address record { @xmldata:Namespace { - prefix: "ns0", + prefix: "ns0", uri: "http://sample.com/test" } string street; @xmldata:Namespace { - prefix: "ns0", + prefix: "ns0", uri: "http://sample.com/test" } string city; @xmldata:Namespace { - prefix: "ns0", + prefix: "ns0", uri: "http://sample.com/test" } string country; @@ -18,7 +18,7 @@ type Ns0_Address record { type Ns0_Codes record { @xmldata:Namespace { - prefix: "ns0", + prefix: "ns0", uri: "http://sample.com/test" } int[] code; @@ -33,27 +33,27 @@ type Ns0_Codes record { } type Ns0_BookStore record { @xmldata:Namespace { - prefix: "ns0", + prefix: "ns0", uri: "http://sample.com/test" } string storeName; @xmldata:Namespace { - prefix: "ns0", + prefix: "ns0", uri: "http://sample.com/test" } int postalCode; @xmldata:Namespace { - prefix: "ns0", + prefix: "ns0", uri: "http://sample.com/test" } boolean isOpen; @xmldata:Namespace { - prefix: "ns0", + prefix: "ns0", uri: "http://sample.com/test" } Ns0_Address address; @xmldata:Namespace { - prefix: "ns0", + prefix: "ns0", uri: "http://sample.com/test" } Ns0_Codes codes; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_9.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_9.bal index a8c4d8e39f20..27f224c92693 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_9.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_9.bal @@ -12,7 +12,7 @@ type Ns2_Null record { type Ns2_Array record { @xmldata:Namespace { - prefix: "ns2", + prefix: "ns2", uri: "http://namespace2.com" } string[] item; @@ -20,27 +20,27 @@ type Ns2_Array record { type Ns2_Element2 record { @xmldata:Namespace { - prefix: "ns2", + prefix: "ns2", uri: "http://namespace2.com" } string subelement; @xmldata:Namespace { - prefix: "ns2", + prefix: "ns2", uri: "http://namespace2.com" } decimal number; @xmldata:Namespace { - prefix: "ns2", + prefix: "ns2", uri: "http://namespace2.com" } boolean 'boolean; @xmldata:Namespace { - prefix: "ns2", + prefix: "ns2", uri: "http://namespace2.com" } Ns2_Null 'null; @xmldata:Namespace { - prefix: "ns2", + prefix: "ns2", uri: "http://namespace2.com" } Ns2_Array array; @@ -51,12 +51,12 @@ type Ns2_Element2 record { } type Root record { @xmldata:Namespace { - prefix: "ns1", + prefix: "ns1", uri: "http://namespace1.com" } Ns1_Element1 element1; @xmldata:Namespace { - prefix: "ns2", + prefix: "ns2", uri: "http://namespace2.com" } Ns2_Element2 element2; From 95c710fec6d0995d75decb85c3bf87f6a67d9906 Mon Sep 17 00:00:00 2001 From: mindula Date: Thu, 4 Apr 2024 16:03:25 +0530 Subject: [PATCH 11/13] Address review suggestions --- .../XMLToRecordConverter.java | 85 +++++++++++-------- .../XMLToRecordConverterTests.java | 28 ++++++ .../test/resources/ballerina/sample_22.bal | 42 +++++++++ .../test/resources/ballerina/sample_23.bal | 48 +++++++++++ .../src/test/resources/xml/sample_22.xml | 16 ++++ .../src/test/resources/xml/sample_23.xml | 9 ++ 6 files changed, 194 insertions(+), 34 deletions(-) create mode 100644 misc/xml-to-record-converter/src/test/resources/ballerina/sample_22.bal create mode 100644 misc/xml-to-record-converter/src/test/resources/ballerina/sample_23.bal create mode 100644 misc/xml-to-record-converter/src/test/resources/xml/sample_22.xml create mode 100644 misc/xml-to-record-converter/src/test/resources/xml/sample_23.xml diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index 1e220af30506..d2402060578b 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -94,7 +94,8 @@ private XMLToRecordConverter() {} private static final String COLON = ":"; public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean isRecordTypeDesc, boolean isClosed, - boolean forceFormatRecordFields, String value, + boolean forceFormatRecordFields, + String fieldNameForLeafAttribute, boolean withNameSpaces) { Map recordToTypeDescNodes = new LinkedHashMap<>(); Map recordToAnnotationNodes = new LinkedHashMap<>(); @@ -114,7 +115,7 @@ public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean is Element rootElement = doc.getDocumentElement(); generateRecords(rootElement, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages, value, withNameSpaces); + recordToElementNodes, diagnosticMessages, fieldNameForLeafAttribute, withNameSpaces); } catch (ParserConfigurationException parserConfigurationException) { DiagnosticMessage message = DiagnosticMessage.xmlToRecordConverter100(null); diagnosticMessages.add(message); @@ -174,6 +175,15 @@ public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean is return DiagnosticUtils.getDiagnosticResponse(diagnosticMessages, response); } + /** + * This method converts the provided XML value to a record. + * + * @param xmlValue The XML value to be converted to a record. + * @param isRecordTypeDesc Whether the record is a type descriptor. + * @param isClosed Whether the record is closed or not. + * @param forceFormatRecordFields Whether to force format the result. + * @return {@link XMLToRecordResponse} The response object containing the converted record. + */ public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeDesc, boolean isClosed, boolean forceFormatRecordFields) { return convertXMLToRecord(xmlValue, isRecordTypeDesc, isClosed, forceFormatRecordFields, null, true); @@ -184,7 +194,7 @@ private static void generateRecords(Element xmlElement, boolean isClosed, Map recordToAnnotationsNodes, Map recordToElementNodes, List diagnosticMessages, - String value, boolean withNameSpace) { + String fieldNameForLeafAttribute, boolean withNameSpace) { Token recordKeyWord = AbstractNodeFactory.createToken(SyntaxKind.RECORD_KEYWORD); Token bodyStartDelimiter = AbstractNodeFactory.createToken(isClosed ? SyntaxKind.OPEN_BRACE_PIPE_TOKEN : SyntaxKind.OPEN_BRACE_TOKEN); @@ -192,7 +202,8 @@ private static void generateRecords(Element xmlElement, boolean isClosed, String xmlNodeName = xmlElement.getNodeName(); List recordFields = getRecordFieldsForXMLElement(xmlElement, isClosed, recordToTypeDescNodes, - recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages, value, withNameSpace); + recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages, fieldNameForLeafAttribute, + withNameSpace); if (recordToTypeDescNodes.containsKey(xmlNodeName)) { RecordTypeDescriptorNode previousRecordTypeDescriptorNode = (RecordTypeDescriptorNode) recordToTypeDescNodes.get(xmlNodeName); @@ -225,28 +236,20 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole Map recordToAnnotationNodes, Map recordToElementNodes, List diagnosticMessages, - String value, boolean withNameSpace) { + String fieldNameForLeafAttribute, boolean withNameSpace) { List recordFields = new ArrayList<>(); String xmlNodeName = xmlElement.getNodeName(); org.w3c.dom.NodeList xmlNodeList = xmlElement.getChildNodes(); - NamedNodeMap xmlAttributesMap = xmlElement.getAttributes(); - Set attributeNames = new HashSet<>(); - for (int j = 0; j < xmlAttributesMap.getLength(); j++) { - attributeNames.add(xmlAttributesMap.item(j).getNodeName()); - } for (int i = 0; i < xmlNodeList.getLength(); i++) { org.w3c.dom.Node xmlNode = xmlNodeList.item(i); if (xmlNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { Element xmlElementNode = (Element) xmlNode; - if (attributeNames.contains(xmlElementNode.getNodeName())) { - continue; - } boolean isLeafXMLElementNode = isLeafXMLElementNode(xmlElementNode); if (!isLeafXMLElementNode || xmlElementNode.getAttributes().getLength() > 0) { generateRecords(xmlElementNode, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages, value, withNameSpace); + recordToElementNodes, diagnosticMessages, fieldNameForLeafAttribute, withNameSpace); } RecordFieldNode recordField = getRecordField(xmlElementNode, false, withNameSpace); if (recordFields.stream().anyMatch(recField -> ((RecordFieldNode) recField).fieldName().text() @@ -267,16 +270,27 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole } } } + NamedNodeMap xmlAttributesMap = xmlElement.getAttributes(); + Set elementNames = new HashSet<>(); + for (int j = 0; j < xmlNodeList.getLength(); j++) { + elementNames.add(xmlNodeList.item(j).getNodeName()); + } for (int i = 0; i < xmlAttributesMap.getLength(); i++) { org.w3c.dom.Node xmlNode = xmlAttributesMap.item(i); if (xmlNode.getNodeType() == org.w3c.dom.Node.ATTRIBUTE_NODE) { - if (xmlElement.getPrefix() != null && - xmlNode.getPrefix() != null && - xmlNode.getPrefix().equals(XMLNS_PREFIX) && - xmlElement.getPrefix().equals(xmlNode.getLocalName()) && withNameSpace) { - AnnotationNode xmlNSNode = getXMLNamespaceNode(xmlNode.getLocalName(), xmlNode.getNodeValue()); + if ((xmlNode.getPrefix() == null && + XMLNS_PREFIX.equals(xmlNode.getLocalName())) || (XMLNS_PREFIX.equals(xmlNode.getPrefix()) && + xmlNode.getLocalName().equals(xmlElement.getPrefix()))) { + String prefix = null; + if (xmlElement.getPrefix() != null && xmlElement.getPrefix().equals(xmlNode.getLocalName())) { + prefix = xmlNode.getLocalName(); + } + AnnotationNode xmlNSNode = getXMLNamespaceNode(prefix, xmlNode.getNodeValue()); recordToAnnotationNodes.put(xmlNodeName, xmlNSNode); } else if (!isLeafXMLElementNode(xmlElement) && !XMLNS_PREFIX.equals(xmlNode.getPrefix())) { + if (elementNames.contains(xmlNode.getNodeName())) { + continue; + } Node recordField = getRecordField(xmlNode); recordFields.add(recordField); } @@ -284,8 +298,8 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole } if (isLeafXMLElementNode(xmlElement) && xmlElement.getAttributes().getLength() > 0) { Token fieldType = AbstractNodeFactory.createToken(SyntaxKind.STRING_KEYWORD); - IdentifierToken fieldName = AbstractNodeFactory.createIdentifierToken(value == null ? - escapeIdentifier("#content") : value); + IdentifierToken fieldName = AbstractNodeFactory.createIdentifierToken(fieldNameForLeafAttribute == null ? + escapeIdentifier("#content") : fieldNameForLeafAttribute); Token semicolon = AbstractNodeFactory.createToken(SyntaxKind.SEMICOLON_TOKEN); RecordFieldNode recordFieldNode = NodeFactory.createRecordFieldNode(null, null, fieldType, fieldName, null, semicolon); @@ -380,7 +394,7 @@ private static List updateRecordFields(Map previo } private static RecordFieldNode getRecordField(Element xmlElementNode, boolean isOptionalField, - boolean hasNameSpace) { + boolean withNameSpace) { Token typeName; Token questionMarkToken = AbstractNodeFactory.createToken(SyntaxKind.QUESTION_MARK_TOKEN); IdentifierToken fieldName = @@ -402,11 +416,11 @@ private static RecordFieldNode getRecordField(Element xmlElementNode, boolean is MetadataNode metadataNode = NodeFactory.createMetadataNode(null, annotationNodes); TypeDescriptorNode fieldTypeName = NodeFactory.createBuiltinSimpleNameReferenceNode(typeName.kind(), typeName); - if (!hasNameSpace) { + if (!withNameSpace) { return NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, optionalFieldToken, semicolonToken); } - return xmlElementNode.getPrefix() == null ? NodeFactory.createRecordFieldNode(null, null, fieldTypeName, + return xmlElementNode.getNamespaceURI() == null ? NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, optionalFieldToken, semicolonToken) : NodeFactory.createRecordFieldNode( metadataNode, null, fieldTypeName, fieldName, optionalFieldToken, semicolonToken); } @@ -576,16 +590,19 @@ private static AnnotationNode getXMLNamespaceNode(String prefix, String uri) { Token closeBrace = AbstractNodeFactory.createToken(SyntaxKind.CLOSE_BRACE_TOKEN); MinutiaeList emptyMinutiaeList = AbstractNodeFactory.createEmptyMinutiaeList(); - IdentifierToken prefixFieldName = AbstractNodeFactory.createIdentifierToken("prefix"); - LiteralValueToken prefixLiteralToken = - NodeFactory.createLiteralValueToken(SyntaxKind.STRING_LITERAL_TOKEN, String.format("\"%s\"", prefix), - emptyMinutiaeList, emptyMinutiaeList); - BasicLiteralNode prefixValueExpr = - NodeFactory.createBasicLiteralNode(SyntaxKind.STRING_LITERAL, prefixLiteralToken); - MappingFieldNode prefixMappingField = - NodeFactory.createSpecificFieldNode(null, prefixFieldName, colon, prefixValueExpr); - mappingFields.add(prefixMappingField); - mappingFields.add(NodeFactory.createToken(SyntaxKind.COMMA_TOKEN)); + if (prefix != null) { + IdentifierToken prefixFieldName = AbstractNodeFactory.createIdentifierToken("prefix"); + LiteralValueToken prefixLiteralToken = + NodeFactory.createLiteralValueToken(SyntaxKind.STRING_LITERAL_TOKEN, + String.format("\"%s\"", prefix), emptyMinutiaeList, emptyMinutiaeList); + BasicLiteralNode prefixValueExpr = + NodeFactory.createBasicLiteralNode(SyntaxKind.STRING_LITERAL, prefixLiteralToken); + MappingFieldNode prefixMappingField = + NodeFactory.createSpecificFieldNode(null, prefixFieldName, colon, prefixValueExpr); + mappingFields.add(prefixMappingField); + mappingFields.add(NodeFactory.createToken(SyntaxKind.COMMA_TOKEN)); + } + IdentifierToken uriFieldName = AbstractNodeFactory.createIdentifierToken("uri"); LiteralValueToken uriLiteralToken = NodeFactory.createLiteralValueToken(SyntaxKind.STRING_LITERAL_TOKEN, String.format("\"%s\"", uri), diff --git a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java index 90c8b00d9cc4..c7b2c2da2de3 100644 --- a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java +++ b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java @@ -149,6 +149,16 @@ public class XMLToRecordConverterTests { private final Path sample21Bal = RES_DIR.resolve(BAL_DIR) .resolve("sample_21.bal"); + private final Path sample22XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_22.xml"); + private final Path sample22Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_22.bal"); + + private final Path sample23XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_23.xml"); + private final Path sample23Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_23.bal"); + private static final String XMLToRecordServiceEP = "xmlToRecord/convert"; @@ -350,6 +360,24 @@ public void testXMLWithMultipleAttributesAndNamespacesWithAnnotations() throws I Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } + @Test(description = "testXMLWithoutNamespacePrefix") + public void testXMLWithoutNamespacePrefix() throws IOException { + String xmlFileContent = Files.readString(sample22XML); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord(xmlFileContent, false, false, false, + null, true).getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample22Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + + @Test(description = "testXMLWithConflictingElementAndAttributeNames") + public void testXMLWithConflictingElementAndAttributeNames() throws IOException { + String xmlFileContent = Files.readString(sample23XML); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord(xmlFileContent, false, false, false, + null, true).getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample23Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + @Test(description = "testXMLToRecordService") public void testXMLToRecordService() throws IOException, ExecutionException, InterruptedException { Endpoint serviceEndpoint = TestUtil.initializeLanguageSever(); diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_22.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_22.bal new file mode 100644 index 000000000000..f8c8f101ff17 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_22.bal @@ -0,0 +1,42 @@ +type Book record { + @xmldata:Namespace { + uri: "http://example.com/library" + } + (int|string) title; + @xmldata:Namespace { + uri: "http://example.com/library" + } + string author; + @xmldata:Namespace { + uri: "http://example.com/library" + } + string genre; +}; + +type Magazine record { + @xmldata:Namespace { + uri: "http://example.com/library" + } + string title; + @xmldata:Namespace { + uri: "http://example.com/library" + } + string issue; +}; + +@xmldata:Name { + value: "library" +} +@xmldata:Namespace { + uri: "http://example.com/library" +} +type Library record { + @xmldata:Namespace { + uri: "http://example.com/library" + } + Book[] book; + @xmldata:Namespace { + uri: "http://example.com/library" + } + Magazine magazine; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_23.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_23.bal new file mode 100644 index 000000000000..9743b6d8e30d --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_23.bal @@ -0,0 +1,48 @@ +type Book_Title record { + string \#content; + @xmldata:Attribute + string edition; + @xmldata:Attribute + string lang; +}; + +type Book_Author record { + string \#content; + @xmldata:Attribute + string gender; + @xmldata:Attribute + string nationality; +}; + +type Book_Book record { + @xmldata:Namespace { + prefix: "book", + uri: "http://example.com/books" + } + Book_Title title; + @xmldata:Namespace { + prefix: "book", + uri: "http://example.com/books" + } + Book_Author author; + @xmldata:Namespace { + prefix: "book", + uri: "http://example.com/books" + } + string publish_date; + @xmldata:Namespace { + prefix: "book", + uri: "http://example.com/books" + } + string description; +}; + +@xmldata:Name {value: "library"} +type Library record { + @xmldata:Namespace { + prefix: "book", + uri: "http://example.com/books" + } + Book_Book book; + string genre; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_22.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_22.xml new file mode 100644 index 000000000000..bb48c97c4dc7 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_22.xml @@ -0,0 +1,16 @@ + + + The Great Gatsby + F. Scott Fitzgerald + Drama + + + 1984 + George Orwell + Dystopian Fiction + + + National Geographic + April 2024 + + diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_23.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_23.xml new file mode 100644 index 000000000000..43c0d407c109 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_23.xml @@ -0,0 +1,9 @@ + + + XML Developer's Guide + Gambardella, Matthew + 2000-10-01 + An in-depth look at creating applications with XML. + + Programming + From 50de57ea3d36f7d583e388c8700652c6f5789f4c Mon Sep 17 00:00:00 2001 From: mindula Date: Thu, 4 Apr 2024 17:11:28 +0530 Subject: [PATCH 12/13] Change variable fieldNameForLeafAttribute to textFieldName --- .../XMLToRecordConverter.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index d2402060578b..a2f172933161 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -95,8 +95,7 @@ private XMLToRecordConverter() {} public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean isRecordTypeDesc, boolean isClosed, boolean forceFormatRecordFields, - String fieldNameForLeafAttribute, - boolean withNameSpaces) { + String textFieldName, boolean withNameSpaces) { Map recordToTypeDescNodes = new LinkedHashMap<>(); Map recordToAnnotationNodes = new LinkedHashMap<>(); Map recordToElementNodes = new LinkedHashMap<>(); @@ -115,7 +114,7 @@ public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean is Element rootElement = doc.getDocumentElement(); generateRecords(rootElement, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages, fieldNameForLeafAttribute, withNameSpaces); + recordToElementNodes, diagnosticMessages, textFieldName, withNameSpaces); } catch (ParserConfigurationException parserConfigurationException) { DiagnosticMessage message = DiagnosticMessage.xmlToRecordConverter100(null); diagnosticMessages.add(message); @@ -181,12 +180,12 @@ public static XMLToRecordResponse convertXMLToRecord(String xmlValue, boolean is * @param xmlValue The XML value to be converted to a record. * @param isRecordTypeDesc Whether the record is a type descriptor. * @param isClosed Whether the record is closed or not. - * @param forceFormatRecordFields Whether to force format the result. + * @param textFieldName Whether to force format the result. * @return {@link XMLToRecordResponse} The response object containing the converted record. */ public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeDesc, boolean isClosed, - boolean forceFormatRecordFields) { - return convertXMLToRecord(xmlValue, isRecordTypeDesc, isClosed, forceFormatRecordFields, null, true); + boolean textFieldName) { + return convertXMLToRecord(xmlValue, isRecordTypeDesc, isClosed, textFieldName, null, true); } private static void generateRecords(Element xmlElement, boolean isClosed, @@ -194,7 +193,7 @@ private static void generateRecords(Element xmlElement, boolean isClosed, Map recordToAnnotationsNodes, Map recordToElementNodes, List diagnosticMessages, - String fieldNameForLeafAttribute, boolean withNameSpace) { + String textFieldName, boolean withNameSpace) { Token recordKeyWord = AbstractNodeFactory.createToken(SyntaxKind.RECORD_KEYWORD); Token bodyStartDelimiter = AbstractNodeFactory.createToken(isClosed ? SyntaxKind.OPEN_BRACE_PIPE_TOKEN : SyntaxKind.OPEN_BRACE_TOKEN); @@ -202,7 +201,7 @@ private static void generateRecords(Element xmlElement, boolean isClosed, String xmlNodeName = xmlElement.getNodeName(); List recordFields = getRecordFieldsForXMLElement(xmlElement, isClosed, recordToTypeDescNodes, - recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages, fieldNameForLeafAttribute, + recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages, textFieldName, withNameSpace); if (recordToTypeDescNodes.containsKey(xmlNodeName)) { RecordTypeDescriptorNode previousRecordTypeDescriptorNode = @@ -236,7 +235,7 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole Map recordToAnnotationNodes, Map recordToElementNodes, List diagnosticMessages, - String fieldNameForLeafAttribute, boolean withNameSpace) { + String textFieldName, boolean withNameSpace) { List recordFields = new ArrayList<>(); String xmlNodeName = xmlElement.getNodeName(); @@ -249,7 +248,7 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole boolean isLeafXMLElementNode = isLeafXMLElementNode(xmlElementNode); if (!isLeafXMLElementNode || xmlElementNode.getAttributes().getLength() > 0) { generateRecords(xmlElementNode, isClosed, recordToTypeDescNodes, recordToAnnotationNodes, - recordToElementNodes, diagnosticMessages, fieldNameForLeafAttribute, withNameSpace); + recordToElementNodes, diagnosticMessages, textFieldName, withNameSpace); } RecordFieldNode recordField = getRecordField(xmlElementNode, false, withNameSpace); if (recordFields.stream().anyMatch(recField -> ((RecordFieldNode) recField).fieldName().text() @@ -298,8 +297,8 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole } if (isLeafXMLElementNode(xmlElement) && xmlElement.getAttributes().getLength() > 0) { Token fieldType = AbstractNodeFactory.createToken(SyntaxKind.STRING_KEYWORD); - IdentifierToken fieldName = AbstractNodeFactory.createIdentifierToken(fieldNameForLeafAttribute == null ? - escapeIdentifier("#content") : fieldNameForLeafAttribute); + IdentifierToken fieldName = AbstractNodeFactory.createIdentifierToken(textFieldName == null ? + escapeIdentifier("#content") : textFieldName); Token semicolon = AbstractNodeFactory.createToken(SyntaxKind.SEMICOLON_TOKEN); RecordFieldNode recordFieldNode = NodeFactory.createRecordFieldNode(null, null, fieldType, fieldName, null, semicolon); From 8a3614e47a4b82c484cb47a10334aeeaf48ace75 Mon Sep 17 00:00:00 2001 From: mindula Date: Thu, 4 Apr 2024 22:11:25 +0530 Subject: [PATCH 13/13] Add more tests --- .../xmltorecordconverter/XMLToRecordConverter.java | 2 +- .../XMLToRecordConverterTests.java | 14 ++++++++++++++ .../src/test/resources/ballerina/sample_24.bal | 12 ++++++++++++ .../src/test/resources/xml/sample_24.xml | 8 ++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 misc/xml-to-record-converter/src/test/resources/ballerina/sample_24.bal create mode 100644 misc/xml-to-record-converter/src/test/resources/xml/sample_24.xml diff --git a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java index a2f172933161..b1418366218b 100644 --- a/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java +++ b/misc/xml-to-record-converter/src/main/java/io/ballerina/xmltorecordconverter/XMLToRecordConverter.java @@ -279,7 +279,7 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole if (xmlNode.getNodeType() == org.w3c.dom.Node.ATTRIBUTE_NODE) { if ((xmlNode.getPrefix() == null && XMLNS_PREFIX.equals(xmlNode.getLocalName())) || (XMLNS_PREFIX.equals(xmlNode.getPrefix()) && - xmlNode.getLocalName().equals(xmlElement.getPrefix()))) { + xmlNode.getLocalName().equals(xmlElement.getPrefix())) && withNameSpace) { String prefix = null; if (xmlElement.getPrefix() != null && xmlElement.getPrefix().equals(xmlNode.getLocalName())) { prefix = xmlNode.getLocalName(); diff --git a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java index c7b2c2da2de3..1a713220b1fa 100644 --- a/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java +++ b/misc/xml-to-record-converter/src/test/java/io/ballerina/xmltorecordconverter/XMLToRecordConverterTests.java @@ -159,6 +159,11 @@ public class XMLToRecordConverterTests { private final Path sample23Bal = RES_DIR.resolve(BAL_DIR) .resolve("sample_23.bal"); + private final Path sample24XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_24.xml"); + private final Path sample24Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_24.bal"); + private static final String XMLToRecordServiceEP = "xmlToRecord/convert"; @@ -378,6 +383,15 @@ public void testXMLWithConflictingElementAndAttributeNames() throws IOException Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } + @Test(description = "testXMLWithoutNamespaces") + public void testXMLWithoutNamespaces() throws IOException { + String xmlFileContent = Files.readString(sample24XML); + String generatedCodeBlock = XMLToRecordConverter.convertXMLToRecord(xmlFileContent, false, false, false, + null, false).getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample24Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + @Test(description = "testXMLToRecordService") public void testXMLToRecordService() throws IOException, ExecutionException, InterruptedException { Endpoint serviceEndpoint = TestUtil.initializeLanguageSever(); diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_24.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_24.bal new file mode 100644 index 000000000000..358fe421e7ae --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_24.bal @@ -0,0 +1,12 @@ +type Book_BookItem record { + string[] authorName; +}; + +type Book_BookList record { + Book_BookItem bookItem; +}; + +@xmldata:Name {value: "library"} +type Example_Library record { + Book_BookList bookList; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_24.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_24.xml new file mode 100644 index 000000000000..3ed7bf752ab7 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_24.xml @@ -0,0 +1,8 @@ + + + + Value 1 + Value 2 + + +