diff --git a/poi-ooxml/build.gradle b/poi-ooxml/build.gradle index 412880b6092..155a81bea33 100644 --- a/poi-ooxml/build.gradle +++ b/poi-ooxml/build.gradle @@ -143,6 +143,7 @@ dependencies { // see https://logging.apache.org/log4j/2.x/log4j-slf4j-impl/ testImplementation "org.apache.logging.log4j:log4j-slf4j18-impl:${log4jVersion}" + testRuntimeOnly 'net.sf.saxon:Saxon-HE:10.6' broken("org.apache.xmlgraphics:batik-script:${batikVersion}"){ exclude group: 'xalan', module: 'xalan' diff --git a/poi-ooxml/src/test/java/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java b/poi-ooxml/src/test/java/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java index cd7f4a5c3cf..7e4dd4e3cce 100644 --- a/poi-ooxml/src/test/java/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java +++ b/poi-ooxml/src/test/java/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java @@ -17,6 +17,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.poi.xssf.extractor; +import static org.apache.poi.xssf.usermodel.XSSFRelation.NS_SPREADSHEETML; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -25,13 +26,16 @@ Licensed to the Apache Software Foundation (ASF) under one or more import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.StringReader; import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Date; -import java.util.regex.Matcher; +import java.util.*; import java.util.regex.Pattern; +import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.apache.poi.ooxml.POIXMLDocumentPart; @@ -46,6 +50,9 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.apache.poi.xssf.usermodel.XSSFMap; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.junit.jupiter.api.Test; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; @@ -186,26 +193,30 @@ void testMultiTable() throws Exception { assertNotNull(map); XSSFExportToXml exporter = new XSSFExportToXml(map); - UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream(); - exporter.exportToXML(os, true); - String xml = os.toString("UTF-8"); - + String xml; + try (UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { + exporter.exportToXML(os, true); + xml = os.toString("UTF-8"); + } assertNotNull(xml); - String[] regexConditions = { - "", - "", - "", - "DataBinding", - "Map Append=\"false\" AutoFit=\"false\" ID=\"1\"", - "Map Append=\"false\" AutoFit=\"false\" ID=\"5\"", - }; - - for (String condition : regexConditions) { - Pattern pattern = Pattern.compile(condition); - Matcher matcher = pattern.matcher(xml); - assertTrue(matcher.find()); - } + Document xmlDoc = XMLHelper.newDocumentBuilder().parse(new InputSource(new StringReader(xml))); + + XPathFactory xpathFactory = XPathFactory.newInstance(); + XPath xpath = xpathFactory.newXPath(); + xpath.setNamespaceContext(new XPathNSContext()); + assertNotNull(xpath.evaluate("/ss:MapInfo", xmlDoc, XPathConstants.NODE)); + assertNotNull(xpath.evaluate( + "/ss:MapInfo/ss:Schema[@ID=\"1\" and @Namespace=\"\" and @SchemaRef=\"\"]", xmlDoc, XPathConstants.NODE)); + assertNotNull(xpath.evaluate( + "/ss:MapInfo/ss:Schema[@ID=\"4\" and @Namespace=\"\" and @SchemaRef=\"\"]", xmlDoc, XPathConstants.NODE)); + NodeList databindingList = (NodeList) xpath.evaluate( + "/ss:MapInfo/ss:Map/ss:DataBinding", xmlDoc, XPathConstants.NODESET); + assertEquals(5, databindingList.getLength()); + assertNotNull(xpath.evaluate( + "/ss:MapInfo/ss:Map[@ID=\"1\" and @Append=\"false\" and @AutoFit=\"false\"]", xmlDoc, XPathConstants.NODE)); + assertNotNull(xpath.evaluate( + "/ss:MapInfo/ss:Map[@ID=\"5\" and @Append=\"false\" and @AutoFit=\"false\"]", xmlDoc, XPathConstants.NODE)); } found = true; @@ -665,4 +676,24 @@ void testXXEInSchema() throws Exception { } } } + + private class XPathNSContext implements NamespaceContext { + final Map nsMap = new HashMap<>(); + + XPathNSContext() { + nsMap.put("ss", NS_SPREADSHEETML); + } + + public String getNamespaceURI(String prefix) { + return nsMap.get(prefix); + } + @SuppressWarnings("rawtypes") + @Override + public Iterator getPrefixes(String val) { + return null; + } + public String getPrefix(String uri) { + return null; + } + } } diff --git a/poi/build.gradle b/poi/build.gradle index fbf2ba4725c..db7ae7998eb 100644 --- a/poi/build.gradle +++ b/poi/build.gradle @@ -54,6 +54,7 @@ dependencies { testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" testImplementation 'org.apiguardian:apiguardian-api:1.1.2' + testRuntimeOnly 'net.sf.saxon:Saxon-HE:10.6' // needed for locating the external references javadocs project(':poi-ooxml') diff --git a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/CertificateKeyEncryptor.java b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/CertificateKeyEncryptor.java index 938b04f4668..706ec93f2e7 100644 --- a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/CertificateKeyEncryptor.java +++ b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/CertificateKeyEncryptor.java @@ -17,13 +17,12 @@ Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.poi.poifs.crypt.agile; -import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getBinAttr; -import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setBinAttr; - import org.apache.poi.EncryptedDocumentException; import org.w3c.dom.Document; import org.w3c.dom.Element; +import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.*; + public class CertificateKeyEncryptor { /** @@ -60,9 +59,9 @@ public CertificateKeyEncryptor(Element certificateKey) { void write(Element encryption) { Document doc = encryption.getOwnerDocument(); - Element keyEncryptor = (Element) encryption.appendChild(doc.createElement("keyEncryptor")); + Element keyEncryptor = (Element) encryption.appendChild(doc.createElementNS(ENC_NS, "keyEncryptor")); keyEncryptor.setAttribute("uri", KeyEncryptor.CERT_NS); - Element encryptedKey = (Element) keyEncryptor.appendChild(doc.createElement("c:encryptedKey")); + Element encryptedKey = (Element) keyEncryptor.appendChild(doc.createElementNS(KeyEncryptor.CERT_NS, "c:encryptedKey")); setBinAttr(encryptedKey, "encryptedKeyValue", encryptedKeyValue); setBinAttr(encryptedKey, "x509Certificate", x509Certificate); diff --git a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/DataIntegrity.java b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/DataIntegrity.java index 5d067b02324..37c90e49046 100644 --- a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/DataIntegrity.java +++ b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/DataIntegrity.java @@ -59,7 +59,7 @@ public DataIntegrity(Element parent) { void write(Element encryption) { Document doc = encryption.getOwnerDocument(); - Element dataIntegrity = (Element)encryption.appendChild(doc.createElement("dataIntegrity")); + Element dataIntegrity = (Element)encryption.appendChild(doc.createElementNS(ENC_NS, "dataIntegrity")); setBinAttr(dataIntegrity, "encryptedHmacKey", encryptedHmacKey); setBinAttr(dataIntegrity, "encryptedHmacValue", encryptedHmacValue); } diff --git a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/EncryptionDocument.java b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/EncryptionDocument.java index fd5e53a2b9b..659507a574d 100644 --- a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/EncryptionDocument.java +++ b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/EncryptionDocument.java @@ -76,7 +76,7 @@ public void write(Document doc) { if (dataIntegrity != null) { dataIntegrity.write(encryption); } - Element keyEncryptors = (Element)encryption.appendChild(doc.createElement("keyEncryptors")); + Element keyEncryptors = (Element)encryption.appendChild(doc.createElementNS(ENC_NS, "keyEncryptors")); boolean hasPass = false; boolean hasCert = false; for (KeyEncryptor ke : this.keyEncryptors) { diff --git a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/KeyData.java b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/KeyData.java index fba57eb2c45..5ed0d14db3d 100644 --- a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/KeyData.java +++ b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/KeyData.java @@ -71,7 +71,7 @@ public KeyData(Element parent) { void write(Element encryption) { Document doc = encryption.getOwnerDocument(); - Element keyData = (Element)encryption.appendChild(doc.createElement("keyData")); + Element keyData = (Element)encryption.appendChild(doc.createElementNS(ENC_NS, "keyData")); setIntAttr(keyData, "saltSize", saltSize); setIntAttr(keyData, "blockSize", blockSize); setIntAttr(keyData, "keyBits", keyBits); diff --git a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/PasswordKeyEncryptor.java b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/PasswordKeyEncryptor.java index 1e3f8640ff9..c31caaba40c 100644 --- a/poi/src/main/java/org/apache/poi/poifs/crypt/agile/PasswordKeyEncryptor.java +++ b/poi/src/main/java/org/apache/poi/poifs/crypt/agile/PasswordKeyEncryptor.java @@ -17,12 +17,6 @@ Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.poi.poifs.crypt.agile; -import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getBinAttr; -import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.getIntAttr; -import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setAttr; -import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setBinAttr; -import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.setIntAttr; - import org.apache.poi.EncryptedDocumentException; import org.apache.poi.poifs.crypt.ChainingMode; import org.apache.poi.poifs.crypt.CipherAlgorithm; @@ -30,6 +24,9 @@ Licensed to the Apache Software Foundation (ASF) under one or more import org.w3c.dom.Document; import org.w3c.dom.Element; +import static org.apache.poi.poifs.crypt.agile.EncryptionDocument.*; +import static org.apache.poi.poifs.crypt.agile.KeyEncryptor.PASS_NS; + public class PasswordKeyEncryptor { /** @@ -124,9 +121,9 @@ public PasswordKeyEncryptor(Element passwordKey) { void write(Element encryption) { Document doc = encryption.getOwnerDocument(); - Element keyEncryptor = (Element) encryption.appendChild(doc.createElement("keyEncryptor")); - keyEncryptor.setAttribute("uri", KeyEncryptor.PASS_NS); - Element encryptedKey = (Element) keyEncryptor.appendChild(doc.createElement("p:encryptedKey")); + Element keyEncryptor = (Element) encryption.appendChild(doc.createElementNS(ENC_NS, "keyEncryptor")); + keyEncryptor.setAttribute("uri", PASS_NS); + Element encryptedKey = (Element) keyEncryptor.appendChild(doc.createElementNS(PASS_NS, "p:encryptedKey")); setIntAttr(encryptedKey, "saltSize", saltSize); setIntAttr(encryptedKey, "blockSize", blockSize); diff --git a/poi/src/main/java9/module-info.class b/poi/src/main/java9/module-info.class index a27868cdf4a..7ca4ecd882a 100644 Binary files a/poi/src/main/java9/module-info.class and b/poi/src/main/java9/module-info.class differ