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 91d52eb8816e..253e1507553e 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 @@ -308,17 +308,18 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole if (((xmlNode.getPrefix() == null && XMLNS_PREFIX.equals(xmlNode.getLocalName())) || (XMLNS_PREFIX.equals(xmlNode.getPrefix()) && xmlNode.getLocalName().equals(xmlElement.getPrefix()))) && withNameSpace) { - String prefix = null; + String prefix = xmlElement.getPrefix(); 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())) { + } else if (!isLeafXMLElementNode(xmlElement) && !XMLNS_PREFIX.equals(xmlNode.getPrefix()) + && !XMLNS_PREFIX.equals(xmlNode.getLocalName())) { if (elementNames.contains(xmlNode.getNodeName())) { continue; } - Node recordField = getRecordField(xmlNode); + Node recordField = getRecordField(xmlNode, withNameSpace); recordFields.add(recordField); } } @@ -331,17 +332,20 @@ private static List getRecordFieldsForXMLElement(Element xmlElement, boole return recordFields; } Token fieldType = getPrimitiveTypeName(xmlElement.getFirstChild().getNodeValue()); + TypeDescriptorNode fieldTypeName = NodeFactory.createBuiltinSimpleNameReferenceNode( + fieldType.kind(), fieldType); IdentifierToken fieldName = AbstractNodeFactory.createIdentifierToken(textFieldName == null ? escapeIdentifier("#content") : textFieldName); Token semicolon = AbstractNodeFactory.createToken(SyntaxKind.SEMICOLON_TOKEN); - RecordFieldNode recordFieldNode = NodeFactory.createRecordFieldNode(null, null, fieldType, + RecordFieldNode recordFieldNode = NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, null, semicolon); recordFields.add(recordFieldNode); for (int j = 0; j < attributeLength; j++) { org.w3c.dom.Node xmlAttributeNode = xmlElement.getAttributes().item(j); if (xmlAttributeNode.getNodeType() == org.w3c.dom.Node.ATTRIBUTE_NODE - && !XMLNS_PREFIX.equals(xmlAttributeNode.getPrefix())) { - Node recordField = getRecordField(xmlAttributeNode); + && !XMLNS_PREFIX.equals(xmlAttributeNode.getPrefix()) + && !XMLNS_PREFIX.equals(xmlAttributeNode.getLocalName())) { + Node recordField = getRecordField(xmlAttributeNode, withNameSpace); recordFields.add(recordField); } } @@ -503,15 +507,20 @@ private static RecordFieldNode getRecordField(Element xmlElementNode, boolean is metadataNode, null, fieldTypeName, fieldName, optionalFieldToken, semicolonToken); } - private static Node getRecordField(org.w3c.dom.Node xmlAttributeNode) { + private static Node getRecordField(org.w3c.dom.Node xmlAttributeNode, boolean withNamespace) { Token typeName = AbstractNodeFactory.createToken(SyntaxKind.STRING_KEYWORD); TypeDescriptorNode fieldTypeName = NodeFactory.createBuiltinSimpleNameReferenceNode(typeName.kind(), typeName); IdentifierToken fieldName = AbstractNodeFactory.createIdentifierToken(escapeIdentifier(xmlAttributeNode.getLocalName())); Token equalToken = AbstractNodeFactory.createToken(SyntaxKind.EQUAL_TOKEN); Token semicolonToken = AbstractNodeFactory.createToken(SyntaxKind.SEMICOLON_TOKEN); - NodeList annotations = AbstractNodeFactory.createNodeList(getXMLAttributeNode()); - MetadataNode metadataNode = NodeFactory.createMetadataNode(null, annotations); + List annotations = new ArrayList<>(); + if (withNamespace && xmlAttributeNode.getPrefix() != null && xmlAttributeNode.getNamespaceURI() != null) { + annotations.add(getXMLNamespaceNode(xmlAttributeNode.getPrefix(), xmlAttributeNode.getNamespaceURI())); + } + annotations.add(getXMLAttributeNode()); + NodeList annotationNodes = NodeFactory.createNodeList(annotations); + MetadataNode metadataNode = NodeFactory.createMetadataNode(null, annotationNodes); if (xmlAttributeNode.getPrefix() != null && xmlAttributeNode.getPrefix().equals(XMLNS_PREFIX)) { 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 d4a7818a9f21..70b9a80c073c 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 @@ -214,6 +214,21 @@ public class XMLToRecordConverterTests { private final Path sample34Bal = RES_DIR.resolve(BAL_DIR) .resolve("sample_34.bal"); + private final Path sample35XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_35.xml"); + private final Path sample35Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_35.bal"); + + private final Path sample36XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_36.xml"); + private final Path sample36Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_36.bal"); + + private final Path sample37XML = RES_DIR.resolve(XML_DIR) + .resolve("sample_37.xml"); + private final Path sample37Bal = RES_DIR.resolve(BAL_DIR) + .resolve("sample_37.bal"); + private static final String XMLToRecordServiceEP = "xmlToRecord/convert"; @@ -549,4 +564,31 @@ public void textXMLWithDefaultValueNode2() throws IOException { String expectedCodeBlock = Files.readString(sample34Bal).replaceAll("\\s+", ""); Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); } + + @Test(description = "textXMLWithDefaultNamespace") + public void textXMLWithDefaultNamespace() throws IOException { + String xmlFileContent = Files.readString(sample35XML); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false, + "__text", true).getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample35Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + + @Test(description = "textXMLWithDefaultNamespace2") + public void textXMLWithDefaultNamespace2() throws IOException { + String xmlFileContent = Files.readString(sample36XML); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false, + "__text", true).getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample36Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } + + @Test(description = "textXMLWithDefaultNamespace3") + public void textXMLWithDefaultNamespace3() throws IOException { + String xmlFileContent = Files.readString(sample37XML); + String generatedCodeBlock = XMLToRecordConverter.convert(xmlFileContent, false, false, false, + "__text", true).getCodeBlock().replaceAll("\\s+", ""); + String expectedCodeBlock = Files.readString(sample37Bal).replaceAll("\\s+", ""); + Assert.assertEquals(generatedCodeBlock, expectedCodeBlock); + } } diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_27.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_27.bal index 88eae813663e..d6a3f4032e9f 100644 --- a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_27.bal +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_27.bal @@ -7,8 +7,6 @@ type Customer record { string loyalty; @xmldata:Attribute string optedInNewsLetter; - @xmldata:Attribute - string 'xmlns; }; type Item record { @@ -21,8 +19,6 @@ type Item record { type Items record { Item[] item; - @xmldata:Attribute - string 'xmlns; }; type Order record { @@ -30,12 +26,8 @@ type Order record { Customer customer; Items items; decimal total; - @xmldata:Attribute - string 'xmlns; }; type Orders record { Order[] 'order; - @xmldata:Attribute - string 'xmlns; }; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_35.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_35.bal new file mode 100644 index 000000000000..4c6c14ffbc8b --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_35.bal @@ -0,0 +1,37 @@ +@xmldata:Namespace { + prefix: "ns2", + uri: "example2.com" +} +type Ns2_Person record { + int __text; + @xmldata:Attribute + string age; + @xmldata:Namespace { + prefix: "ns2", + uri: "example2.com" + } + @xmldata:Attribute + string name; +}; + +type Data record { + @xmldata:Namespace { + prefix: "ns2", + uri: "example2.com" + } + Ns2_Person Person; + @xmldata:Namespace { + uri: "example.com" + } + string Message; +}; + +@xmldata:Namespace { + uri: "example.com" +} +type AQ record { + @xmldata:Namespace { + uri: "example.com" + } + Data Data; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_36.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_36.bal new file mode 100644 index 000000000000..f8e88bd3b90a --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_36.bal @@ -0,0 +1,63 @@ +@xmldata:Namespace { + prefix: "ns2", + uri: "example3.com" +} +type Ns2_Person record { + int __text; + @xmldata:Namespace { + prefix: "ns2", + uri: "example2.com" + } + @xmldata:Attribute + string age; + @xmldata:Namespace { + prefix: "ns2", + uri: "example2.com" + } + @xmldata:Attribute + string name; +}; + +type Ns1_Details record { + @xmldata:Namespace { + prefix: "ns1", + uri: "example1.com" + } + string Info; + @xmldata:Namespace { + prefix: "ns1", + uri: "example1.com" + } + string Status; +}; + +type Data record { + @xmldata:Namespace { + prefix: "ns2", + uri: "example2.com" + } + Ns2_Person Person; + @xmldata:Namespace { + uri: "example.com" + } + string C; + @xmldata:Namespace { + prefix: "ns1", + uri: "example1.com" + } + Ns1_Details Details; + @xmldata:Namespace { + uri: "example.com" + } + string B; +}; + +@xmldata:Namespace { + uri: "example.com" +} +type Test record { + @xmldata:Namespace { + uri: "example.com" + } + Data Data; +}; diff --git a/misc/xml-to-record-converter/src/test/resources/ballerina/sample_37.bal b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_37.bal new file mode 100644 index 000000000000..280803518d20 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/ballerina/sample_37.bal @@ -0,0 +1,63 @@ +@xmldata:Namespace { + prefix: "ns1", + uri: "example3.com" +} +type Ns1_Person record { + int __text; + @xmldata:Attribute + string age; + @xmldata:Attribute + string city; + @xmldata:Namespace { + prefix: "ns1", + uri: "example1.com" + } + @xmldata:Attribute + string name; +}; + +type Ns2_Details record { + @xmldata:Namespace { + prefix: "ns2", + uri: "example.com" + } + string Info; + @xmldata:Namespace { + prefix: "ns2", + uri: "example.com" + } + string Status; + @xmldata:Attribute + string number; +}; + +type Data record { + @xmldata:Namespace { + prefix: "ns1", + uri: "example1.com" + } + Ns1_Person Person; + @xmldata:Namespace { + uri: "example2.com" + } + string Name; + @xmldata:Namespace { + prefix: "ns2", + uri: "example.com" + } + Ns2_Details Details; + @xmldata:Namespace { + uri: "example2.com" + } + string Description; +}; + +@xmldata:Namespace { + uri: "example2.com" +} +type Countries record { + @xmldata:Namespace { + uri: "example2.com" + } + Data Data; +}; 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 27f224c92693..65e5bbd3c120 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,11 +1,23 @@ type Ns1_Element1 record { + @xmldata:Namespace { + prefix: "ns1", + uri: "http://namespace1.com" + } @xmldata:Attribute string attribute1; + @xmldata:Namespace { + prefix: "ns2", + uri: "http://namespace2.com" + } @xmldata:Attribute string attribute2; }; type Ns2_Null record { + @xmldata:Namespace { + prefix: "xsi", + uri: "http://www.w3.org/2001/XMLSchema-instance" + } @xmldata:Attribute string nil; }; diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_35.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_35.xml new file mode 100644 index 000000000000..52c9280adadf --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_35.xml @@ -0,0 +1,6 @@ + + + 1 + Test + + diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_36.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_36.xml new file mode 100644 index 000000000000..afc8c77fe40c --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_36.xml @@ -0,0 +1,11 @@ + + + 2 + Example + + Additional Info + Active + + Sample + + diff --git a/misc/xml-to-record-converter/src/test/resources/xml/sample_37.xml b/misc/xml-to-record-converter/src/test/resources/xml/sample_37.xml new file mode 100644 index 000000000000..b737df0e71e7 --- /dev/null +++ b/misc/xml-to-record-converter/src/test/resources/xml/sample_37.xml @@ -0,0 +1,11 @@ + + + 2 + Data Sample + + Additional Information + Active + + Sample Text + +