2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2022 Deutsche Telekom AG
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.cps.utils;
23 import java.io.ByteArrayInputStream;
24 import java.io.IOException;
25 import java.io.StringWriter;
26 import java.nio.charset.StandardCharsets;
27 import java.util.HashMap;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
31 import javax.xml.XMLConstants;
32 import javax.xml.parsers.DocumentBuilder;
33 import javax.xml.parsers.DocumentBuilderFactory;
34 import javax.xml.parsers.ParserConfigurationException;
35 import javax.xml.transform.Transformer;
36 import javax.xml.transform.TransformerException;
37 import javax.xml.transform.TransformerFactory;
38 import javax.xml.transform.dom.DOMSource;
39 import javax.xml.transform.stream.StreamResult;
40 import lombok.AccessLevel;
41 import lombok.NoArgsConstructor;
42 import org.onap.cps.spi.exceptions.DataValidationException;
43 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
45 import org.w3c.dom.Document;
46 import org.w3c.dom.Element;
47 import org.xml.sax.SAXException;
49 @NoArgsConstructor(access = AccessLevel.PRIVATE)
50 public class XmlFileUtils {
52 private static DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
53 private static final Pattern XPATH_PROPERTY_REGEX =
54 Pattern.compile("\\[@(\\S{1,100})=['\\\"](\\S{1,100})['\\\"]\\]");
57 * Prepare XML content.
59 * @param xmlContent XML content sent to store
60 * @param schemaContext schema context
62 * @return XML content wrapped by root node (if needed)
64 public static String prepareXmlContent(final String xmlContent, final SchemaContext schemaContext)
65 throws IOException, ParserConfigurationException, TransformerException, SAXException {
66 return addRootNodeToXmlContent(xmlContent, schemaContext.getModules().iterator().next().getName(),
67 YangUtils.DATA_ROOT_NODE_NAMESPACE);
71 * Prepare XML content.
73 * @param xmlContent XML content sent to store
74 * @param parentSchemaNode Parent schema node
75 * @param xpath Parent xpath
77 * @return XML content wrapped by root node (if needed)
79 public static String prepareXmlContent(final String xmlContent,
80 final DataSchemaNode parentSchemaNode,
82 throws IOException, ParserConfigurationException, TransformerException, SAXException {
83 final String namespace = parentSchemaNode.getQName().getNamespace().toString();
84 final String parentXpathPart = xpath.substring(xpath.lastIndexOf('/') + 1);
85 final Matcher regexMatcher = XPATH_PROPERTY_REGEX.matcher(parentXpathPart);
86 if (regexMatcher.find()) {
87 final HashMap<String, String> rootNodePropertyMap = new HashMap<>();
88 rootNodePropertyMap.put(regexMatcher.group(1), regexMatcher.group(2));
89 return addRootNodeToXmlContent(xmlContent, parentSchemaNode.getQName().getLocalName(), namespace,
93 return addRootNodeToXmlContent(xmlContent, parentSchemaNode.getQName().getLocalName(), namespace);
96 private static String addRootNodeToXmlContent(final String xmlContent,
97 final String rootNodeTagName,
98 final String namespace,
99 final Map<String, String> rootNodeProperty)
100 throws IOException, SAXException, ParserConfigurationException, TransformerException {
101 final DocumentBuilder documentBuilder = dbFactory.newDocumentBuilder();
102 final StringBuilder xmlStringBuilder = new StringBuilder();
103 xmlStringBuilder.append(xmlContent);
104 final Document document = documentBuilder.parse(
105 new ByteArrayInputStream(xmlStringBuilder.toString().getBytes(StandardCharsets.UTF_8)));
106 final Element root = document.getDocumentElement();
107 if (!root.getTagName().equals(rootNodeTagName)
108 && !root.getTagName().equals(YangUtils.DATA_ROOT_NODE_TAG_NAME)) {
109 final Document documentWithRootNode = addDataRootNode(root, rootNodeTagName, namespace, rootNodeProperty);
110 documentWithRootNode.setXmlStandalone(true);
111 final TransformerFactory transformerFactory = TransformerFactory.newInstance();
112 transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
113 transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
114 final Transformer transformer = transformerFactory.newTransformer();
115 final StringWriter stringWriter = new StringWriter();
116 transformer.transform(new DOMSource(documentWithRootNode), new StreamResult(stringWriter));
117 return stringWriter.toString();
123 * Add root node to XML content.
125 * @param xmlContent XML content to add root node into
126 * @param rootNodeTagName Root node tag name
127 * @return XML content with root node tag added (if needed)
129 public static String addRootNodeToXmlContent(final String xmlContent,
130 final String rootNodeTagName,
131 final String namespace)
132 throws IOException, ParserConfigurationException, TransformerException, SAXException {
133 return addRootNodeToXmlContent(xmlContent, rootNodeTagName, namespace, new HashMap<>());
137 * Add root node into DOM element.
139 * @param node DOM element to add root node into
140 * @param tagName Root tag name to add
141 * @return DOM element with a root node
143 static Document addDataRootNode(final Element node,
144 final String tagName,
145 final String namespace,
146 final Map<String, String> rootNodeProperty) {
148 final DocumentBuilder docBuilder = dbFactory.newDocumentBuilder();
149 final Document document = docBuilder.newDocument();
150 final Element rootElement = document.createElementNS(namespace, tagName);
151 for (final Map.Entry<String, String> entry : rootNodeProperty.entrySet()) {
152 final Element propertyElement = document.createElement(entry.getKey());
153 propertyElement.setTextContent(entry.getValue());
154 rootElement.appendChild(propertyElement);
156 rootElement.appendChild(document.adoptNode(node));
157 document.appendChild(rootElement);
159 } catch (final ParserConfigurationException exception) {
160 throw new DataValidationException("Can't parse XML", "XML can't be parsed", exception);