UPDATE Added additional tests, security config, and fix format issues (#7421)
This commit is contained in:
parent
a56d3b1e58
commit
a02fcfbb06
@ -3,6 +3,7 @@ package com.baeldung.xml.attribute;
|
|||||||
import org.dom4j.*;
|
import org.dom4j.*;
|
||||||
import org.dom4j.io.DocumentSource;
|
import org.dom4j.io.DocumentSource;
|
||||||
import org.dom4j.io.SAXReader;
|
import org.dom4j.io.SAXReader;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import javax.xml.XMLConstants;
|
import javax.xml.XMLConstants;
|
||||||
import javax.xml.transform.OutputKeys;
|
import javax.xml.transform.OutputKeys;
|
||||||
@ -17,9 +18,12 @@ import java.util.List;
|
|||||||
public class Dom4jTransformer {
|
public class Dom4jTransformer {
|
||||||
private final Document input;
|
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
|
// 1- Build the doc from the XML file
|
||||||
SAXReader xmlReader = new SAXReader();
|
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);
|
this.input = xmlReader.read(resourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,8 @@ public class JaxpTransformer {
|
|||||||
// 1- Build the doc from the XML file
|
// 1- Build the doc from the XML file
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
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);
|
.parse(resourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ public class JaxpTransformer {
|
|||||||
// 2- Locate the node(s) with xpath
|
// 2- Locate the node(s) with xpath
|
||||||
XPath xpath = XPathFactory.newInstance()
|
XPath xpath = XPathFactory.newInstance()
|
||||||
.newXPath();
|
.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
|
// 3- Make the change on the selected nodes
|
||||||
for (int i = 0; i < nodes.getLength(); i++) {
|
for (int i = 0; i < nodes.getLength(); i++) {
|
||||||
Element value = (Element) nodes.item(i);
|
Element value = (Element) nodes.item(i);
|
||||||
@ -57,7 +58,7 @@ public class JaxpTransformer {
|
|||||||
Transformer xformer = factory.newTransformer();
|
Transformer xformer = factory.newTransformer();
|
||||||
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||||
Writer output = new StringWriter();
|
Writer output = new StringWriter();
|
||||||
xformer.transform(new DOMSource(input), new StreamResult(output));
|
xformer.transform(new DOMSource(this.input), new StreamResult(output));
|
||||||
return output.toString();
|
return output.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,19 @@
|
|||||||
package com.baeldung.xml.attribute.jmh;
|
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.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.Runner;
|
||||||
import org.openjdk.jmh.runner.RunnerException;
|
import org.openjdk.jmh.runner.RunnerException;
|
||||||
import org.openjdk.jmh.runner.options.Options;
|
import org.openjdk.jmh.runner.options.Options;
|
||||||
@ -12,28 +24,21 @@ import com.baeldung.xml.attribute.Dom4jTransformer;
|
|||||||
import com.baeldung.xml.attribute.JaxpTransformer;
|
import com.baeldung.xml.attribute.JaxpTransformer;
|
||||||
import com.baeldung.xml.attribute.JooxTransformer;
|
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)
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
public class AttributeBenchMark {
|
public class AttributeBenchMark {
|
||||||
|
|
||||||
public static void main(String[] args) throws RunnerException {
|
public static void main(String[] args) throws RunnerException {
|
||||||
Options opt = new OptionsBuilder()
|
Options opt = new OptionsBuilder().include(AttributeBenchMark.class.getSimpleName())
|
||||||
.include(AttributeBenchMark.class.getSimpleName())
|
|
||||||
.forks(1)
|
.forks(1)
|
||||||
.build();
|
.build();
|
||||||
new Runner(opt).run();
|
new Runner(opt).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public String dom4jBenchmark() throws DocumentException, TransformerException {
|
public String dom4jBenchmark() throws DocumentException, TransformerException, SAXException {
|
||||||
String path = getClass()
|
String path = this.getClass()
|
||||||
.getResource("/xml/attribute.xml")
|
.getResource("/xml/attribute.xml")
|
||||||
.toString();
|
.toString();
|
||||||
Dom4jTransformer transformer = new Dom4jTransformer(path);
|
Dom4jTransformer transformer = new Dom4jTransformer(path);
|
||||||
@ -46,7 +51,7 @@ public class AttributeBenchMark {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public String jooxBenchmark() throws IOException, SAXException {
|
public String jooxBenchmark() throws IOException, SAXException {
|
||||||
String path = getClass()
|
String path = this.getClass()
|
||||||
.getResource("/xml/attribute.xml")
|
.getResource("/xml/attribute.xml")
|
||||||
.toString();
|
.toString();
|
||||||
JooxTransformer transformer = new JooxTransformer(path);
|
JooxTransformer transformer = new JooxTransformer(path);
|
||||||
@ -59,7 +64,7 @@ public class AttributeBenchMark {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public String jaxpBenchmark() throws TransformerException, ParserConfigurationException, SAXException, IOException, XPathExpressionException {
|
public String jaxpBenchmark() throws TransformerException, ParserConfigurationException, SAXException, IOException, XPathExpressionException {
|
||||||
String path = getClass()
|
String path = this.getClass()
|
||||||
.getResource("/xml/attribute.xml")
|
.getResource("/xml/attribute.xml")
|
||||||
.toString();
|
.toString();
|
||||||
JaxpTransformer transformer = new JaxpTransformer(path);
|
JaxpTransformer transformer = new JaxpTransformer(path);
|
||||||
|
@ -2,14 +2,19 @@ package com.baeldung.xml.attribute;
|
|||||||
|
|
||||||
import org.dom4j.DocumentException;
|
import org.dom4j.DocumentException;
|
||||||
import org.junit.jupiter.api.Test;
|
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.TransformerException;
|
||||||
import javax.xml.transform.TransformerFactoryConfigurationError;
|
import javax.xml.transform.TransformerFactoryConfigurationError;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,9 +23,8 @@ import static org.xmlunit.assertj.XmlAssert.assertThat;
|
|||||||
public class Dom4jProcessorUnitTest {
|
public class Dom4jProcessorUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenXmlWithAttributes_whenModifyAttribute_thenGetXmlUpdated() throws TransformerFactoryConfigurationError, TransformerException, DocumentException {
|
public void givenXmlWithAttributes_whenModifyAttribute_thenGetXmlUpdated() throws TransformerFactoryConfigurationError, TransformerException, DocumentException, SAXException {
|
||||||
String path = getClass()
|
String path = getClass().getResource("/xml/attribute.xml")
|
||||||
.getResource("/xml/attribute.xml")
|
|
||||||
.toString();
|
.toString();
|
||||||
Dom4jTransformer transformer = new Dom4jTransformer(path);
|
Dom4jTransformer transformer = new Dom4jTransformer(path);
|
||||||
String attribute = "customer";
|
String attribute = "customer";
|
||||||
@ -33,23 +37,32 @@ public class Dom4jProcessorUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenTwoXml_whenModifyAttribute_thenGetSimilarXml() throws IOException, TransformerFactoryConfigurationError, TransformerException, URISyntaxException, DocumentException {
|
public void givenTwoXml_whenModifyAttribute_thenGetSimilarXml() throws IOException, TransformerFactoryConfigurationError, TransformerException, URISyntaxException, DocumentException, SAXException {
|
||||||
String path = getClass()
|
String path = getClass().getResource("/xml/attribute.xml")
|
||||||
.getResource("/xml/attribute.xml")
|
|
||||||
.toString();
|
.toString();
|
||||||
Dom4jTransformer transformer = new Dom4jTransformer(path);
|
Dom4jTransformer transformer = new Dom4jTransformer(path);
|
||||||
String attribute = "customer";
|
String attribute = "customer";
|
||||||
String oldValue = "true";
|
String oldValue = "true";
|
||||||
String newValue = "false";
|
String newValue = "false";
|
||||||
String expectedXml = new String(Files.readAllBytes((Paths.get(getClass()
|
String expectedXml = new String(Files.readAllBytes((Paths.get(getClass().getResource("/xml/attribute_expected.xml")
|
||||||
.getResource("/xml/attribute_expected.xml")
|
|
||||||
.toURI()))));
|
.toURI()))));
|
||||||
|
|
||||||
String result = transformer.modifyAttribute(attribute, oldValue, newValue);
|
String result = transformer.modifyAttribute(attribute, oldValue, newValue);
|
||||||
|
|
||||||
assertThat(result)
|
assertThat(result).and(expectedXml)
|
||||||
.and(expectedXml)
|
|
||||||
.areSimilar();
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.baeldung.xml.attribute;
|
package com.baeldung.xml.attribute;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -11,6 +12,7 @@ import javax.xml.xpath.XPathExpressionException;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.SAXParseException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit test for {@link JaxpTransformer}.
|
* Unit test for {@link JaxpTransformer}.
|
||||||
@ -31,4 +33,16 @@ public class JaxpProcessorUnitTest {
|
|||||||
assertThat(result).hasXPath("//*[contains(@customer, 'false')]");
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,19 @@ package com.baeldung.xml.attribute;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.xml.sax.SAXException;
|
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.transform.TransformerFactoryConfigurationError;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,8 +24,7 @@ public class JooxProcessorUnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenXmlWithAttributes_whenModifyAttribute_thenGetXmlUpdated() throws IOException, SAXException, TransformerFactoryConfigurationError {
|
public void givenXmlWithAttributes_whenModifyAttribute_thenGetXmlUpdated() throws IOException, SAXException, TransformerFactoryConfigurationError {
|
||||||
String path = getClass()
|
String path = getClass().getResource("/xml/attribute.xml")
|
||||||
.getResource("/xml/attribute.xml")
|
|
||||||
.toString();
|
.toString();
|
||||||
JooxTransformer transformer = new JooxTransformer(path);
|
JooxTransformer transformer = new JooxTransformer(path);
|
||||||
String attribute = "customer";
|
String attribute = "customer";
|
||||||
@ -33,22 +38,31 @@ public class JooxProcessorUnitTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenTwoXml_whenModifyAttribute_thenGetSimilarXml() throws IOException, TransformerFactoryConfigurationError, URISyntaxException, SAXException {
|
public void givenTwoXml_whenModifyAttribute_thenGetSimilarXml() throws IOException, TransformerFactoryConfigurationError, URISyntaxException, SAXException {
|
||||||
String path = getClass()
|
String path = getClass().getResource("/xml/attribute.xml")
|
||||||
.getResource("/xml/attribute.xml")
|
|
||||||
.toString();
|
.toString();
|
||||||
JooxTransformer transformer = new JooxTransformer(path);
|
JooxTransformer transformer = new JooxTransformer(path);
|
||||||
String attribute = "customer";
|
String attribute = "customer";
|
||||||
String oldValue = "true";
|
String oldValue = "true";
|
||||||
String newValue = "false";
|
String newValue = "false";
|
||||||
String expectedXml = new String(Files.readAllBytes((Paths.get(getClass()
|
String expectedXml = new String(Files.readAllBytes((Paths.get(getClass().getResource("/xml/attribute_expected.xml")
|
||||||
.getResource("/xml/attribute_expected.xml")
|
|
||||||
.toURI()))));
|
.toURI()))));
|
||||||
|
|
||||||
String result = transformer.modifyAttribute(attribute, oldValue, newValue);
|
String result = transformer.modifyAttribute(attribute, oldValue, newValue);
|
||||||
|
|
||||||
assertThat(result)
|
assertThat(result).and(expectedXml)
|
||||||
.and(expectedXml)
|
|
||||||
.areSimilar();
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
9
xml/src/test/resources/xml/xee_attribute.xml
Normal file
9
xml/src/test/resources/xml/xee_attribute.xml
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user