Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support new options in xml conversion #42440

Merged
merged 13 commits into from
Apr 5, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -91,8 +93,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,
mindula marked this conversation as resolved.
Show resolved Hide resolved
boolean forceFormatRecordFields,
String textFieldName, boolean withNameSpaces) {
Map<String, NonTerminalNode> recordToTypeDescNodes = new LinkedHashMap<>();
Map<String, AnnotationNode> recordToAnnotationNodes = new LinkedHashMap<>();
Map<String, Element> recordToElementNodes = new LinkedHashMap<>();
Expand All @@ -111,7 +114,7 @@ public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeD

Element rootElement = doc.getDocumentElement();
generateRecords(rootElement, isClosed, recordToTypeDescNodes, recordToAnnotationNodes,
recordToElementNodes, diagnosticMessages);
recordToElementNodes, diagnosticMessages, textFieldName, withNameSpaces);
} catch (ParserConfigurationException parserConfigurationException) {
DiagnosticMessage message = DiagnosticMessage.xmlToRecordConverter100(null);
diagnosticMessages.add(message);
Expand Down Expand Up @@ -154,7 +157,7 @@ public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeD
}).toList();

NodeList<ModuleMemberDeclarationNode> moduleMembers =
AbstractNodeFactory.createNodeList(new ArrayList<>(typeDefNodes));;
AbstractNodeFactory.createNodeList(new ArrayList<>(typeDefNodes));

Token eofToken = AbstractNodeFactory.createIdentifierToken("");
ModulePartNode modulePartNode = NodeFactory.createModulePartNode(imports, moduleMembers, eofToken);
Expand All @@ -171,19 +174,35 @@ public static XMLToRecordResponse convert(String xmlValue, boolean isRecordTypeD
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 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 textFieldName) {
return convertXMLToRecord(xmlValue, isRecordTypeDesc, isClosed, textFieldName, null, true);
}

private static void generateRecords(Element xmlElement, boolean isClosed,
Map<String, NonTerminalNode> recordToTypeDescNodes,
Map<String, AnnotationNode> recordToAnnotationsNodes,
Map<String, Element> recordToElementNodes,
List<DiagnosticMessage> diagnosticMessages) {
List<DiagnosticMessage> diagnosticMessages,
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);

String xmlNodeName = xmlElement.getNodeName();

List<Node> recordFields = getRecordFieldsForXMLElement(xmlElement, isClosed, recordToTypeDescNodes,
recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages);
recordToAnnotationsNodes, recordToElementNodes, diagnosticMessages, textFieldName,
withNameSpace);
if (recordToTypeDescNodes.containsKey(xmlNodeName)) {
RecordTypeDescriptorNode previousRecordTypeDescriptorNode =
(RecordTypeDescriptorNode) recordToTypeDescNodes.get(xmlNodeName);
Expand Down Expand Up @@ -215,7 +234,8 @@ private static List<Node> getRecordFieldsForXMLElement(Element xmlElement, boole
Map<String, NonTerminalNode> recordToTypeDescNodes,
Map<String, AnnotationNode> recordToAnnotationNodes,
Map<String, Element> recordToElementNodes,
List<DiagnosticMessage> diagnosticMessages) {
List<DiagnosticMessage> diagnosticMessages,
String textFieldName, boolean withNameSpace) {
List<Node> recordFields = new ArrayList<>();

String xmlNodeName = xmlElement.getNodeName();
Expand All @@ -226,11 +246,11 @@ private static List<Node> getRecordFieldsForXMLElement(Element xmlElement, boole
if (xmlNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
Element xmlElementNode = (Element) xmlNode;
boolean isLeafXMLElementNode = isLeafXMLElementNode(xmlElementNode);
if (!isLeafXMLElementNode) {
if (!isLeafXMLElementNode || xmlElementNode.getAttributes().getLength() > 0) {
generateRecords(xmlElementNode, isClosed, recordToTypeDescNodes, recordToAnnotationNodes,
recordToElementNodes, diagnosticMessages);
recordToElementNodes, diagnosticMessages, textFieldName, withNameSpace);
}
RecordFieldNode recordField = getRecordField(xmlElementNode, false);
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())
Expand All @@ -250,21 +270,47 @@ private static List<Node> getRecordFieldsForXMLElement(Element xmlElement, boole
}
}
NamedNodeMap xmlAttributesMap = xmlElement.getAttributes();
Set<String> 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())) {
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())) && withNameSpace) {
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 {
} else if (!isLeafXMLElementNode(xmlElement) && !XMLNS_PREFIX.equals(xmlNode.getPrefix())) {
if (elementNames.contains(xmlNode.getNodeName())) {
continue;
}
Node recordField = getRecordField(xmlNode);
recordFields.add(recordField);
}
}
}
if (isLeafXMLElementNode(xmlElement) && xmlElement.getAttributes().getLength() > 0) {
Token fieldType = AbstractNodeFactory.createToken(SyntaxKind.STRING_KEYWORD);
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);
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);
}
}
}

return recordFields;
}
Expand Down Expand Up @@ -346,32 +392,43 @@ private static List<Node> updateRecordFields(Map<String, RecordFieldNode> previo
return updatedRecordFields;
}

private static RecordFieldNode getRecordField(Element xmlElementNode, boolean isOptionalField) {
private static RecordFieldNode getRecordField(Element xmlElementNode, boolean isOptionalField,
boolean withNameSpace) {
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
String elementKey = xmlElementNode.getNodeName().trim();
String type = getRecordName(elementKey);
typeName = AbstractNodeFactory.createIdentifierToken(type);
}
List<AnnotationNode> xmlNameNode = List.of(getXMLNamespaceNode(xmlElementNode.getPrefix(),
xmlElementNode.getNamespaceURI()));
NodeList<AnnotationNode> 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 (!withNameSpace) {
return NodeFactory.createRecordFieldNode(null, null, fieldTypeName, fieldName, optionalFieldToken,
semicolonToken);
}
return xmlElementNode.getNamespaceURI() == 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) {
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.getNodeName()));
AbstractNodeFactory.createIdentifierToken(escapeIdentifier(xmlAttributeNode.getLocalName()));
Token equalToken = AbstractNodeFactory.createToken(SyntaxKind.EQUAL_TOKEN);
Token semicolonToken = AbstractNodeFactory.createToken(SyntaxKind.SEMICOLON_TOKEN);
NodeList<AnnotationNode> annotations = AbstractNodeFactory.createNodeList(getXMLAttributeNode());
Expand Down Expand Up @@ -532,16 +589,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),
Expand Down
Loading
Loading