UPDATE Added additional tests, security config, and fix format issues (#7421)

This commit is contained in:
Juan Moreno 2019-08-05 19:35:34 -03:00 committed by KevinGilmore
parent a56d3b1e58
commit a02fcfbb06
7 changed files with 116 additions and 56 deletions

View File

@ -3,6 +3,7 @@ package com.baeldung.xml.attribute;
import org.dom4j.*;
import org.dom4j.io.DocumentSource;
import org.dom4j.io.SAXReader;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.transform.OutputKeys;
@ -17,9 +18,12 @@ import java.util.List;
public class Dom4jTransformer {
private final Document input;
public Dom4jTransformer(String resourcePath) throws DocumentException {
public Dom4jTransformer(String resourcePath) throws DocumentException, SAXException {
// 1- Build the doc from the XML file
SAXReader xmlReader = new SAXReader();
xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false);
xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
this.input = xmlReader.read(resourcePath);
}

View File

@ -32,7 +32,8 @@ public class JaxpTransformer {
// 1- Build the doc from the XML file
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
input = factory.newDocumentBuilder()
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
this.input = factory.newDocumentBuilder()
.parse(resourcePath);
}
@ -40,24 +41,24 @@ public class JaxpTransformer {
// 2- Locate the node(s) with xpath
XPath xpath = XPathFactory.newInstance()
.newXPath();
NodeList nodes = (NodeList) xpath.evaluate(String.format("//*[contains(@%s, '%s')]", attribute, oldValue), input, XPathConstants.NODESET);
NodeList nodes = (NodeList) xpath.evaluate(String.format("//*[contains(@%s, '%s')]", attribute, oldValue), this.input, XPathConstants.NODESET);
// 3- Make the change on the selected nodes
for (int i = 0; i < nodes.getLength(); i++) {
Element value = (Element) nodes.item(i);
value.setAttribute(attribute, newValue);
}
//Stream api syntax
// IntStream
// .range(0, nodes.getLength())
// .mapToObj(i -> (Element) nodes.item(i))
// .forEach(value -> value.setAttribute(attribute, newValue));
// Stream api syntax
// IntStream
// .range(0, nodes.getLength())
// .mapToObj(i -> (Element) nodes.item(i))
// .forEach(value -> value.setAttribute(attribute, newValue));
// 4- Save the result to a new XML doc
TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Transformer xformer = factory.newTransformer();
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
Writer output = new StringWriter();
xformer.transform(new DOMSource(input), new StreamResult(output));
xformer.transform(new DOMSource(this.input), new StreamResult(output));
return output.toString();
}
}

View File

@ -1,7 +1,19 @@
package com.baeldung.xml.attribute.jmh;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPathExpressionException;
import org.dom4j.DocumentException;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
@ -12,30 +24,23 @@ import com.baeldung.xml.attribute.Dom4jTransformer;
import com.baeldung.xml.attribute.JaxpTransformer;
import com.baeldung.xml.attribute.JooxTransformer;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPathExpressionException;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class AttributeBenchMark {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(AttributeBenchMark.class.getSimpleName())
.forks(1)
.build();
Options opt = new OptionsBuilder().include(AttributeBenchMark.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
@Benchmark
public String dom4jBenchmark() throws DocumentException, TransformerException {
String path = getClass()
.getResource("/xml/attribute.xml")
.toString();
public String dom4jBenchmark() throws DocumentException, TransformerException, SAXException {
String path = this.getClass()
.getResource("/xml/attribute.xml")
.toString();
Dom4jTransformer transformer = new Dom4jTransformer(path);
String attribute = "customer";
String oldValue = "true";
@ -46,9 +51,9 @@ public class AttributeBenchMark {
@Benchmark
public String jooxBenchmark() throws IOException, SAXException {
String path = getClass()
.getResource("/xml/attribute.xml")
.toString();
String path = this.getClass()
.getResource("/xml/attribute.xml")
.toString();
JooxTransformer transformer = new JooxTransformer(path);
String attribute = "customer";
String oldValue = "true";
@ -59,9 +64,9 @@ public class AttributeBenchMark {
@Benchmark
public String jaxpBenchmark() throws TransformerException, ParserConfigurationException, SAXException, IOException, XPathExpressionException {
String path = getClass()
.getResource("/xml/attribute.xml")
.toString();
String path = this.getClass()
.getResource("/xml/attribute.xml")
.toString();
JaxpTransformer transformer = new JaxpTransformer(path);
String attribute = "customer";
String oldValue = "true";

View File

@ -2,14 +2,19 @@ package com.baeldung.xml.attribute;
import org.dom4j.DocumentException;
import org.junit.jupiter.api.Test;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.xpath.XPathExpressionException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.xmlunit.assertj.XmlAssert.assertThat;
/**
@ -18,10 +23,9 @@ import static org.xmlunit.assertj.XmlAssert.assertThat;
public class Dom4jProcessorUnitTest {
@Test
public void givenXmlWithAttributes_whenModifyAttribute_thenGetXmlUpdated() throws TransformerFactoryConfigurationError, TransformerException, DocumentException {
String path = getClass()
.getResource("/xml/attribute.xml")
.toString();
public void givenXmlWithAttributes_whenModifyAttribute_thenGetXmlUpdated() throws TransformerFactoryConfigurationError, TransformerException, DocumentException, SAXException {
String path = getClass().getResource("/xml/attribute.xml")
.toString();
Dom4jTransformer transformer = new Dom4jTransformer(path);
String attribute = "customer";
String oldValue = "true";
@ -33,23 +37,32 @@ public class Dom4jProcessorUnitTest {
}
@Test
public void givenTwoXml_whenModifyAttribute_thenGetSimilarXml() throws IOException, TransformerFactoryConfigurationError, TransformerException, URISyntaxException, DocumentException {
String path = getClass()
.getResource("/xml/attribute.xml")
.toString();
public void givenTwoXml_whenModifyAttribute_thenGetSimilarXml() throws IOException, TransformerFactoryConfigurationError, TransformerException, URISyntaxException, DocumentException, SAXException {
String path = getClass().getResource("/xml/attribute.xml")
.toString();
Dom4jTransformer transformer = new Dom4jTransformer(path);
String attribute = "customer";
String oldValue = "true";
String newValue = "false";
String expectedXml = new String(Files.readAllBytes((Paths.get(getClass()
.getResource("/xml/attribute_expected.xml")
.toURI()))));
String expectedXml = new String(Files.readAllBytes((Paths.get(getClass().getResource("/xml/attribute_expected.xml")
.toURI()))));
String result = transformer.modifyAttribute(attribute, oldValue, newValue);
assertThat(result)
.and(expectedXml)
.areSimilar();
assertThat(result).and(expectedXml)
.areSimilar();
}
@Test
public void givenXmlXee_whenInit_thenThrowException() throws IOException, SAXException, ParserConfigurationException, XPathExpressionException, TransformerFactoryConfigurationError, TransformerException {
String path = getClass().getResource("/xml/xee_attribute.xml")
.toString();
assertThatThrownBy(() -> {
new Dom4jTransformer(path);
}).isInstanceOf(DocumentException.class);
}
}

View File

@ -1,5 +1,6 @@
package com.baeldung.xml.attribute;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.xmlunit.assertj.XmlAssert.assertThat;
import java.io.IOException;
@ -11,6 +12,7 @@ import javax.xml.xpath.XPathExpressionException;
import org.junit.jupiter.api.Test;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Unit test for {@link JaxpTransformer}.
@ -31,4 +33,16 @@ public class JaxpProcessorUnitTest {
assertThat(result).hasXPath("//*[contains(@customer, 'false')]");
}
@Test
public void givenXmlXee_whenInit_thenThrowException() throws IOException, SAXException, ParserConfigurationException, XPathExpressionException, TransformerFactoryConfigurationError, TransformerException {
String path = getClass().getResource("/xml/xee_attribute.xml")
.toString();
assertThatThrownBy(() -> {
new JaxpTransformer(path);
}).isInstanceOf(SAXParseException.class);
}
}

View File

@ -2,13 +2,19 @@ package com.baeldung.xml.attribute;
import org.junit.jupiter.api.Test;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.xpath.XPathExpressionException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.xmlunit.assertj.XmlAssert.assertThat;
/**
@ -18,9 +24,8 @@ public class JooxProcessorUnitTest {
@Test
public void givenXmlWithAttributes_whenModifyAttribute_thenGetXmlUpdated() throws IOException, SAXException, TransformerFactoryConfigurationError {
String path = getClass()
.getResource("/xml/attribute.xml")
.toString();
String path = getClass().getResource("/xml/attribute.xml")
.toString();
JooxTransformer transformer = new JooxTransformer(path);
String attribute = "customer";
String oldValue = "true";
@ -33,22 +38,31 @@ public class JooxProcessorUnitTest {
@Test
public void givenTwoXml_whenModifyAttribute_thenGetSimilarXml() throws IOException, TransformerFactoryConfigurationError, URISyntaxException, SAXException {
String path = getClass()
.getResource("/xml/attribute.xml")
.toString();
String path = getClass().getResource("/xml/attribute.xml")
.toString();
JooxTransformer transformer = new JooxTransformer(path);
String attribute = "customer";
String oldValue = "true";
String newValue = "false";
String expectedXml = new String(Files.readAllBytes((Paths.get(getClass()
.getResource("/xml/attribute_expected.xml")
.toURI()))));
String expectedXml = new String(Files.readAllBytes((Paths.get(getClass().getResource("/xml/attribute_expected.xml")
.toURI()))));
String result = transformer.modifyAttribute(attribute, oldValue, newValue);
assertThat(result)
.and(expectedXml)
.areSimilar();
assertThat(result).and(expectedXml)
.areSimilar();
}
@Test
public void givenXmlXee_whenInit_thenThrowException() throws IOException, SAXException, ParserConfigurationException, XPathExpressionException, TransformerFactoryConfigurationError, TransformerException {
String path = getClass().getResource("/xml/xee_attribute.xml")
.toString();
assertThatThrownBy(() -> {
new JooxTransformer(path);
}).isInstanceOf(SAXParseException.class);
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE notification [
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<notification id="5">
<bad_entry>&xxe;
</bad_entry>
<to customer="true">john@email.com</to>
<from>mary@email.com</from>
</notification>