blob: 4ca2e176a9b8ade11b676398447d9fc19993dcb9 [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.apache.ofbiz.base.util;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.apache.ofbiz.widget.model.ThemeFactory;
import org.jsoup.parser.ParseError;
import org.jsoup.parser.Parser;
public final class UtilHtml {
private static final String MODULE = UtilHtml.class.getName();
private static final Parser JSOUP_HTML_PARSER = createJSoupHtmlParser();
private static final String[] TAG_SHOULD_CLOSE_LIST = new String[]{"div"};
private static List<String> visualThemeBasePathsName;
private UtilHtml() { }
private static Parser createJSoupHtmlParser() {
Parser parser = Parser.htmlParser();
parser.setTrackErrors(100);
return parser;
}
public static List<ParseError> validateHtmlFragmentWithJSoup(String content) {
if (content != null) {
JSOUP_HTML_PARSER.parseInput(content, "");
if (JSOUP_HTML_PARSER.isTrackErrors()) {
return JSOUP_HTML_PARSER.getErrors();
}
}
return null;
}
/**
*
* @param content
* @return list of errors
*/
public static List<String> hasUnclosedTag(String content) {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLEventReader eventReader = null;
List<String> errorList = new ArrayList<>();
try {
// wrap with template tag as some content contains multiple root
eventReader = inputFactory.createXMLEventReader(
new ByteArrayInputStream(("<template>" + content + "</template>").getBytes(StandardCharsets.UTF_8)),
"utf-8");
Stack<StartElement> stack = new Stack<StartElement>();
while (eventReader.hasNext()) {
try {
XMLEvent event = eventReader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
stack.push(startElement);
}
if (event.isEndElement()) {
EndElement endElement = event.asEndElement();
stack.pop();
}
} catch (XMLStreamException e) {
if (!stack.isEmpty()) {
StartElement startElement = stack.pop();
String elementName = startElement.getName().getLocalPart();
if (Arrays.stream(TAG_SHOULD_CLOSE_LIST).anyMatch(elementName::equals)) {
errorList.add(e.getMessage());
}
} else {
errorList.add(e.getMessage());
}
break;
}
}
} catch (XMLStreamException e) {
errorList.add(e.getMessage());
} finally {
if (eventReader != null) {
try {
eventReader.close();
} catch (XMLStreamException e) {
Debug.logError(e, MODULE);
}
}
}
return errorList;
}
public static List<String> getVisualThemeFolderNamesToExempt() {
if (visualThemeBasePathsName == null) {
try {
List<File> xmlThemes = ThemeFactory.getThemeXmlFiles();
visualThemeBasePathsName = new ArrayList<>();
String themePathKey = File.separator + "themes" + File.separator;
String pluginPathKey = File.separator + "plugins" + File.separator;
for (File xmlTheme : xmlThemes) {
String path = xmlTheme.toURI().toURL().toString();
// get the path after themes or plugins folders
if (path.indexOf(themePathKey) > 0) {
path = path.substring(path.indexOf(themePathKey) + 8);
} else if (path.indexOf(pluginPathKey) > 0) {
path = path.substring(path.indexOf(pluginPathKey) + 9);
}
// get folder name
path = path.substring(0, path.indexOf(File.separator));
if (!path.contains("common-theme") && !path.contains("ecommerce")) {
visualThemeBasePathsName.add(File.separator + path + File.separator);
}
}
} catch (IOException e) {
Debug.logError(e, MODULE);
}
}
return Collections.unmodifiableList(visualThemeBasePathsName);
}
public static void logHtmlWarning(String content, String location, String error, String module) {
Debug.logWarning("[Parsing " + location + "] " + error, module);
}
}