Fix bug #56814 - Switch from dom4j to JAXP

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1617428 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Uwe Schindler 2014-08-12 07:19:51 +00:00
parent 549f7bc0e6
commit fed01cb1ad
19 changed files with 388 additions and 644 deletions

View File

@ -19,7 +19,6 @@
<classpathentry kind="lib" path="lib/commons-codec-1.9.jar"/>
<classpathentry kind="lib" path="lib/commons-logging-1.1.3.jar"/>
<classpathentry kind="lib" path="lib/log4j-1.2.17.jar"/>
<classpathentry kind="lib" path="ooxml-lib/dom4j-1.6.1.jar"/>
<classpathentry kind="lib" path="ooxml-lib/xmlbeans-2.6.0.jar"/>
<classpathentry kind="lib" path="lib/hamcrest-core-1.3.jar"/>
<classpathentry kind="lib" path="lib/junit-4.11.jar"/>

View File

@ -148,8 +148,6 @@ under the License.
<property name="main.antlauncher.url" value="${repository.m2}/maven2/org/apache/ant/ant-launcher/1.9.4/ant-launcher-1.9.4.jar"/>
<!-- jars in the lib-ooxml directory, see the fetch-ooxml-jars target-->
<property name="ooxml.dom4j.jar" location="${ooxml.lib}/dom4j-1.6.1.jar"/>
<property name="ooxml.dom4j.url" value="${repository.m2}/maven2/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar"/>
<property name="ooxml.xmlbeans23.jar" location="${ooxml.lib}/xmlbeans-2.3.0.jar"/>
<property name="ooxml.xmlbeans23.url"
value="${repository.m2}/maven2/org/apache/xmlbeans/xmlbeans/2.3.0/xmlbeans-2.3.0.jar"/>
@ -221,7 +219,6 @@ under the License.
</path>
<path id="ooxml.classpath">
<pathelement location="${ooxml.dom4j.jar}"/>
<pathelement location="${ooxml.xmlbeans26.jar}"/>
<pathelement location="${ooxml.xsds.jar}"/>
<path refid="main.classpath"/>
@ -251,7 +248,6 @@ under the License.
</path>
<path id="ooxml-lite.classpath">
<pathelement location="${ooxml.dom4j.jar}"/>
<pathelement location="${ooxml.xmlbeans26.jar}"/>
<pathelement location="build/ooxml-xsds-lite"/> <!-- instead of ooxml-xsds.jar use the filtered classes-->
<path refid="main.classpath"/>
@ -429,7 +425,6 @@ under the License.
<condition property="ooxml.jars.present">
<or>
<and>
<available file="${ooxml.dom4j.jar}"/>
<available file="${ooxml.xmlbeans23.jar}"/>
<available file="${ooxml.xmlbeans26.jar}"/>
<available file="${ooxml.xsds.jar}"/>
@ -440,10 +435,6 @@ under the License.
</target>
<target name="fetch-ooxml-jars" depends="check-ooxml-jars" unless="ooxml.jars.present">
<mkdir dir="${ooxml.lib}"/>
<antcall target="downloadfile">
<param name="sourcefile" value="${ooxml.dom4j.url}"/>
<param name="destfile" value="${ooxml.dom4j.jar}"/>
</antcall>
<antcall target="downloadfile">
<param name="sourcefile" value="${ooxml.xmlbeans23.url}"/>
<param name="destfile" value="${ooxml.xmlbeans23.jar}"/>
@ -1288,7 +1279,6 @@ under the License.
<include name="log4j-*.jar"/>
</zipfileset>
<zipfileset dir="${ooxml.lib}" prefix="${zipdir}/ooxml-lib">
<include name="dom4j-*.jar"/>
<include name="xmlbeans-2.6*.jar"/>
</zipfileset>
<zipfileset dir="${dist.dir}" prefix="${zipdir}">
@ -1316,7 +1306,6 @@ under the License.
<include name="log4j-*.jar"/>
</zipfileset>
<tarfileset dir="${ooxml.lib}" prefix="${zipdir}/ooxml-lib">
<include name="dom4j-*.jar"/>
<include name="xmlbeans-2.6*.jar"/>
</tarfileset>
<tarfileset dir="${build.site}" prefix="${zipdir}/docs"/>
@ -1449,7 +1438,6 @@ under the License.
<auxClasspath path="ooxml-lib/ooxml-schemas-1.1.jar" />
<auxClasspath path="ooxml-lib/ooxml-encryption-1.1.jar" />
<auxClasspath path="ooxml-lib/xmlbeans-2.6.0.jar" />
<auxClasspath path="ooxml-lib/dom4j-1.6.1.jar" />
<auxClasspath path="lib/commons-codec-1.9.jar" />
<auxClasspath path="lib/commons-logging-1.1.3.jar" />
<auxClasspath path="lib/junit-4.11.jar" />

View File

@ -229,50 +229,6 @@ Office Open XML schemas (ooxml-schemas-1.1.jar)
[5] http://www.ecma-international.org/publications/files/ECMA-ST/Ecma%20PATENT/Patent%20statements%20ok/ECMA-376%20Adobe%20Patent%20Declaration.pdf
DOM4J library (dom4j-1.6.1.jar)
Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
Redistribution and use of this software and associated documentation
("Software"), with or without modification, are permitted provided
that the following conditions are met:
1. Redistributions of source code must retain copyright
statements and notices. Redistributions must also contain a
copy of this document.
2. Redistributions in binary form must reproduce the
above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
3. The name "DOM4J" must not be used to endorse or promote
products derived from this Software without prior written
permission of MetaStuff, Ltd. For written permission,
please contact dom4j-info@metastuff.com.
4. Products derived from this Software may not be called "DOM4J"
nor may "DOM4J" appear in their names without prior written
permission of MetaStuff, Ltd. DOM4J is a registered
trademark of MetaStuff, Ltd.
5. Due credit should be given to the DOM4J Project -
http://www.dom4j.org
THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
JUnit test library (junit-4.11.jar)
Common Public License - v 1.0

View File

@ -4,9 +4,6 @@ Copyright 2003-2014 The Apache Software Foundation
This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).
This product contains the DOM4J library (http://www.dom4j.org).
Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
This product contains parts that were originally based on software from BEA.
Copyright (c) 2000-2003, BEA Systems, <http://www.bea.com/>.

View File

@ -69,10 +69,5 @@
<artifactId>poi-ooxml-schemas</artifactId>
<version>@VERSION@</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
</project>

View File

@ -116,12 +116,6 @@
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- non-test dependency for OOXMLLite -->
<dependency>
<groupId>junit</groupId>

View File

@ -179,7 +179,7 @@ public class ExcelAntTask extends Task {
throw new BuildException(
"The <classpath> for <excelant> must include poi.jar and poi-ooxml.jar " +
"if not in Ant's own classpath. Processing .xlsx spreadsheets requires " +
"additional poi-ooxml-schemas.jar, xmlbeans.jar and dom4j.jar" ,
"additional poi-ooxml-schemas.jar, xmlbeans.jar" ,
e, getLocation());
}

View File

@ -21,7 +21,7 @@ import java.io.File;
/**
* Storage class for configuration storage parameters.
* TODO xml syntax checking is no longer done with DOM4j parser -> remove the schema or do it ?
* TODO xml syntax checking is not done with JAXP by default -> remove the schema or do it ?
*
* @author CDubettier, Julen Chable
* @version 1.0

View File

@ -27,9 +27,10 @@ import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.SAXHelper;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Represents a collection of PackageRelationship elements that are owned by a
@ -313,22 +314,19 @@ public final class PackageRelationshipCollection implements
Document xmlRelationshipsDoc = SAXHelper.readSAXDocument(relPart.getInputStream());
// Browse default types
Element root = xmlRelationshipsDoc.getRootElement();
Element root = xmlRelationshipsDoc.getDocumentElement();
// Check OPC compliance M4.1 rule
boolean fCorePropertiesRelationship = false;
@SuppressWarnings("unchecked")
Iterator<Element> iter = (Iterator<Element>)
root.elementIterator(PackageRelationship.RELATIONSHIP_TAG_NAME);
while (iter.hasNext()) {
Element element = iter.next();
NodeList nodeList = root.getElementsByTagName(PackageRelationship.RELATIONSHIP_TAG_NAME);
int nodeCount = nodeList.getLength();
for (int i = 0; i < nodeCount; i++) {
Element element = (Element)nodeList.item(i);
// Relationship ID
String id = element.attribute(
PackageRelationship.ID_ATTRIBUTE_NAME).getValue();
String id = element.getAttribute(PackageRelationship.ID_ATTRIBUTE_NAME);
// Relationship type
String type = element.attribute(
PackageRelationship.TYPE_ATTRIBUTE_NAME).getValue();
String type = element.getAttribute(PackageRelationship.TYPE_ATTRIBUTE_NAME);
/* Check OPC Compliance */
// Check Rule M4.1
@ -342,8 +340,7 @@ public final class PackageRelationshipCollection implements
/* End OPC Compliance */
// TargetMode (default value "Internal")
Attribute targetModeAttr = element
.attribute(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME);
Attr targetModeAttr = element.getAttributeNode(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME);
TargetMode targetMode = TargetMode.INTERNAL;
if (targetModeAttr != null) {
targetMode = targetModeAttr.getValue().toLowerCase()
@ -353,9 +350,7 @@ public final class PackageRelationshipCollection implements
// Target converted in URI
URI target = PackagingURIHelper.toURI("http://invalid.uri"); // dummy url
String value = element.attribute(
PackageRelationship.TARGET_ATTRIBUTE_NAME)
.getValue();
String value = element.getAttribute(PackageRelationship.TARGET_ATTRIBUTE_NAME);
try {
// when parsing of the given uri fails, we can either
// ignore this relationship, which leads to IllegalStateException

View File

@ -17,21 +17,36 @@
package org.apache.poi.openxml4j.opc;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
public final class StreamHelper {
private StreamHelper() {
// Do nothing
}
private static final TransformerFactory transformerFactory = TransformerFactory.newInstance();
private static synchronized Transformer getIdentityTransformer() throws TransformerException {
return transformerFactory.newTransformer();
}
/**
* Turning the DOM4j object in the specified output stream.
* Save the document object in the specified output stream.
*
* @param xmlContent
* The XML document.
@ -40,18 +55,34 @@ public final class StreamHelper {
* @return <b>true</b> if the xml is successfully written in the stream,
* else <b>false</b>.
*/
public static boolean saveXmlInStream(Document xmlContent,
OutputStream outStream) {
try {
OutputFormat outformat = OutputFormat.createPrettyPrint();
outformat.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(outStream, outformat);
writer.write(xmlContent);
} catch (Exception e) {
return false;
}
return true;
}
public static boolean saveXmlInStream(Document xmlContent,
OutputStream outStream) {
try {
Transformer trans = getIdentityTransformer();
Source xmlSource = new DOMSource(xmlContent);
// prevent close of stream by transformer:
Result outputTarget = new StreamResult(new FilterOutputStream(
outStream) {
@Override
public void write(byte b[], int off, int len)
throws IOException {
out.write(b, off, len);
}
@Override
public void close() throws IOException {
out.flush(); // only flush, don't close!
}
});
trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.setOutputProperty(OutputKeys.STANDALONE, "yes");
trans.transform(xmlSource, outputTarget);
} catch (TransformerException e) {
return false;
}
return true;
}
/**
* Copy the input stream into the output stream.

View File

@ -17,12 +17,11 @@
package org.apache.poi.openxml4j.opc.internal;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;
@ -33,13 +32,12 @@ import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.util.DocumentHelper;
import org.apache.poi.util.SAXHelper;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Manage package content types ([Content_Types].xml part).
@ -376,38 +374,33 @@ public abstract class ContentTypeManager {
Document xmlContentTypetDoc = SAXHelper.readSAXDocument(in);
// Default content types
List defaultTypes = xmlContentTypetDoc.getRootElement().elements(
DEFAULT_TAG_NAME);
Iterator elementIteratorDefault = defaultTypes.iterator();
while (elementIteratorDefault.hasNext()) {
Element element = (Element) elementIteratorDefault.next();
String extension = element.attribute(EXTENSION_ATTRIBUTE_NAME)
.getValue();
String contentType = element.attribute(
CONTENT_TYPE_ATTRIBUTE_NAME).getValue();
NodeList defaultTypes = xmlContentTypetDoc.getDocumentElement().getElementsByTagName(DEFAULT_TAG_NAME);
int defaultTypeCount = defaultTypes.getLength();
for (int i = 0; i < defaultTypeCount; i++) {
Element element = (Element) defaultTypes.item(i);
String extension = element.getAttribute(EXTENSION_ATTRIBUTE_NAME);
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
addDefaultContentType(extension, contentType);
}
// Overriden content types
List overrideTypes = xmlContentTypetDoc.getRootElement().elements(
OVERRIDE_TAG_NAME);
Iterator elementIteratorOverride = overrideTypes.iterator();
while (elementIteratorOverride.hasNext()) {
Element element = (Element) elementIteratorOverride.next();
URI uri = new URI(element.attribute(PART_NAME_ATTRIBUTE_NAME)
.getValue());
PackagePartName partName = PackagingURIHelper
.createPartName(uri);
String contentType = element.attribute(
CONTENT_TYPE_ATTRIBUTE_NAME).getValue();
NodeList overrideTypes = xmlContentTypetDoc.getDocumentElement().getElementsByTagName(OVERRIDE_TAG_NAME);
int overrideTypeCount = overrideTypes.getLength();
for (int i = 0; i < overrideTypeCount; i++) {
Element element = (Element) overrideTypes.item(i);
URI uri = new URI(element.getAttribute(PART_NAME_ATTRIBUTE_NAME));
PackagePartName partName = PackagingURIHelper.createPartName(uri);
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
addOverrideContentType(partName, contentType);
}
} catch (URISyntaxException urie) {
throw new InvalidFormatException(urie.getMessage());
} catch (DocumentException e) {
throw new InvalidFormatException(e.getMessage());
}
}
} catch (SAXException e) {
throw new InvalidFormatException(e.getMessage());
} catch (IOException e) {
throw new InvalidFormatException(e.getMessage());
}
}
/**
* Save the contents type part.
@ -421,9 +414,8 @@ public abstract class ContentTypeManager {
Document xmlOutDoc = DocumentHelper.createDocument();
// Building namespace
Namespace dfNs = Namespace.get("", TYPES_NAMESPACE_URI);
Element typesElem = xmlOutDoc
.addElement(new QName(TYPES_TAG_NAME, dfNs));
Element typesElem = xmlOutDoc.createElementNS(TYPES_NAMESPACE_URI, TYPES_TAG_NAME);
xmlOutDoc.appendChild(typesElem);
// Adding default types
for (Entry<String, String> entry : defaultContentType.entrySet()) {
@ -454,10 +446,10 @@ public abstract class ContentTypeManager {
*/
private void appendSpecificTypes(Element root,
Entry<PackagePartName, String> entry) {
root.addElement(OVERRIDE_TAG_NAME).addAttribute(
PART_NAME_ATTRIBUTE_NAME,
entry.getKey().getName()).addAttribute(
CONTENT_TYPE_ATTRIBUTE_NAME, entry.getValue());
Element specificType = root.getOwnerDocument().createElement(OVERRIDE_TAG_NAME);
specificType.setAttribute(PART_NAME_ATTRIBUTE_NAME, entry.getKey().getName());
specificType.setAttribute(CONTENT_TYPE_ATTRIBUTE_NAME, entry.getValue());
root.appendChild(specificType);
}
/**
@ -470,11 +462,10 @@ public abstract class ContentTypeManager {
* @see #save(java.io.OutputStream)
*/
private void appendDefaultType(Element root, Entry<String, String> entry) {
root.addElement(DEFAULT_TAG_NAME).addAttribute(
EXTENSION_ATTRIBUTE_NAME, entry.getKey())
.addAttribute(CONTENT_TYPE_ATTRIBUTE_NAME,
entry.getValue());
Element defaultType = root.getOwnerDocument().createElement(DEFAULT_TAG_NAME);
defaultType.setAttribute(EXTENSION_ATTRIBUTE_NAME, entry.getKey());
defaultType.setAttribute(CONTENT_TYPE_ATTRIBUTE_NAME, entry.getValue());
root.appendChild(defaultType);
}
/**

View File

@ -48,8 +48,6 @@ public final class PackagePropertiesPart extends PackagePart implements
public final static String NAMESPACE_DCTERMS_URI = "http://purl.org/dc/terms/";
public final static String NAMESPACE_XSI_URI = "http://www.w3.org/2001/XMLSchema-instance";
/**
* Constructor.
*

View File

@ -17,8 +17,6 @@
package org.apache.poi.openxml4j.opc.internal;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -30,7 +28,7 @@ import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.StreamHelper;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.dom4j.Document;
import org.w3c.dom.Document;
/**
* Zip implementation of the ContentTypeManager.
@ -69,17 +67,8 @@ public class ZipContentTypeManager extends ContentTypeManager {
// Referenced in ZIP
zos.putNextEntry(partEntry);
// Saving data in the ZIP file
ByteArrayOutputStream outTemp = new ByteArrayOutputStream();
StreamHelper.saveXmlInStream(content, out);
InputStream ins = new ByteArrayInputStream(outTemp.toByteArray());
byte[] buff = new byte[ZipHelper.READ_WRITE_FILE_BUFFER_SIZE];
while (ins.available() > 0) {
int resultRead = ins.read(buff);
if (resultRead == -1) {
// end of file reached
break;
}
zos.write(buff, 0, resultRead);
if (!StreamHelper.saveXmlInStream(content, zos)) {
return false;
}
zos.closeEntry();
} catch (IOException ioe) {

View File

@ -19,15 +19,18 @@ package org.apache.poi.openxml4j.opc.internal.marshallers;
import java.io.OutputStream;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import javax.xml.XMLConstants;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.events.Namespace;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart;
import org.apache.poi.openxml4j.opc.internal.PartMarshaller;
import org.apache.poi.openxml4j.util.Nullable;
import org.apache.poi.util.DocumentHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Package properties marshaller.
@ -36,17 +39,15 @@ import org.apache.poi.openxml4j.opc.internal.PartMarshaller;
*/
public class PackagePropertiesMarshaller implements PartMarshaller {
private final static Namespace namespaceDC = new Namespace("dc",
PackagePropertiesPart.NAMESPACE_DC_URI);
private final static Namespace namespaceCoreProperties = new Namespace("",
PackagePropertiesPart.NAMESPACE_CP_URI);
private final static Namespace namespaceDcTerms = new Namespace("dcterms",
PackagePropertiesPart.NAMESPACE_DCTERMS_URI);
private final static Namespace namespaceXSI = new Namespace("xsi",
PackagePropertiesPart.NAMESPACE_XSI_URI);
private final static Namespace namespaceDC, namespaceCoreProperties, namespaceDcTerms, namespaceXSI;
static {
final XMLEventFactory f = XMLEventFactory.newFactory();
namespaceDC = f.createNamespace("dc", PackagePropertiesPart.NAMESPACE_DC_URI);
namespaceCoreProperties = f.createNamespace("cp", PackagePropertiesPart.NAMESPACE_CP_URI);
namespaceDcTerms = f.createNamespace("dcterms", PackagePropertiesPart.NAMESPACE_DCTERMS_URI);
namespaceXSI = f.createNamespace("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
}
protected static final String KEYWORD_CATEGORY = "category";
@ -98,13 +99,13 @@ public class PackagePropertiesMarshaller implements PartMarshaller {
// Configure the document
xmlDoc = DocumentHelper.createDocument();
Element rootElem = xmlDoc.addElement(new QName("coreProperties",
namespaceCoreProperties));
rootElem.addNamespace("cp", PackagePropertiesPart.NAMESPACE_CP_URI);
rootElem.addNamespace("dc", PackagePropertiesPart.NAMESPACE_DC_URI);
rootElem.addNamespace("dcterms",
PackagePropertiesPart.NAMESPACE_DCTERMS_URI);
rootElem.addNamespace("xsi", PackagePropertiesPart.NAMESPACE_XSI_URI);
Element rootElem = xmlDoc.createElementNS(namespaceCoreProperties.getNamespaceURI(),
getQName("coreProperties", namespaceCoreProperties));
DocumentHelper.addNamespaceDeclaration(rootElem, namespaceCoreProperties);
DocumentHelper.addNamespaceDeclaration(rootElem, namespaceDC);
DocumentHelper.addNamespaceDeclaration(rootElem, namespaceDcTerms);
DocumentHelper.addNamespaceDeclaration(rootElem, namespaceXSI);
xmlDoc.appendChild(rootElem);
addCategory();
addContentStatus();
@ -125,197 +126,110 @@ public class PackagePropertiesMarshaller implements PartMarshaller {
return true;
}
/**
/**
* Sets the given element's text content, creating it if necessary.
*/
private Element setElementTextContent(String localName, Namespace namespace, Nullable<String> property) {
return setElementTextContent(localName, namespace, property, property.getValue());
}
private String getQName(String localName, Namespace namespace) {
return namespace.getPrefix().isEmpty() ? localName : namespace.getPrefix() + ':' + localName;
}
private Element setElementTextContent(String localName, Namespace namespace, Nullable<?> property, String propertyValue) {
if (!property.hasValue())
return null;
Element root = xmlDoc.getDocumentElement();
Element elem = (Element) root.getElementsByTagNameNS(namespace.getNamespaceURI(), localName).item(0);
if (elem == null) {
// missing, we add it
elem = xmlDoc.createElementNS(namespace.getNamespaceURI(), getQName(localName, namespace));
root.appendChild(elem);
}
elem.setTextContent(propertyValue);
return elem;
}
private Element setElementTextContent(String localName, Namespace namespace, Nullable<?> property, String propertyValue, String xsiType) {
Element element = setElementTextContent(localName, namespace, property, propertyValue);
if (element != null) {
element.setAttributeNS(namespaceXSI.getNamespaceURI(), getQName("type", namespaceXSI), xsiType);
}
return element;
}
/**
* Add category property element if needed.
*/
private void addCategory() {
if (!propsPart.getCategoryProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_CATEGORY, namespaceCoreProperties));
if (elem == null) {
// Missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_CATEGORY, namespaceCoreProperties));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getCategoryProperty().getValue());
setElementTextContent(KEYWORD_CATEGORY, namespaceCoreProperties, propsPart.getCategoryProperty());
}
/**
* Add content status property element if needed.
*/
private void addContentStatus() {
if (!propsPart.getContentStatusProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_CONTENT_STATUS, namespaceCoreProperties));
if (elem == null) {
// Missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_CONTENT_STATUS, namespaceCoreProperties));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getContentStatusProperty().getValue());
setElementTextContent(KEYWORD_CONTENT_STATUS, namespaceCoreProperties, propsPart.getContentStatusProperty());
}
/**
* Add content type property element if needed.
*/
private void addContentType() {
if (!propsPart.getContentTypeProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_CONTENT_TYPE, namespaceCoreProperties));
if (elem == null) {
// Missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_CONTENT_TYPE, namespaceCoreProperties));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getContentTypeProperty().getValue());
setElementTextContent(KEYWORD_CONTENT_TYPE, namespaceCoreProperties, propsPart.getContentTypeProperty());
}
/**
* Add created property element if needed.
*/
private void addCreated() {
if (!propsPart.getCreatedProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_CREATED, namespaceDcTerms));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_CREATED, namespaceDcTerms));
} else {
elem.clearContent();// clear the old value
}
elem.addAttribute(new QName("type", namespaceXSI), "dcterms:W3CDTF");
elem.addText(propsPart.getCreatedPropertyString());
setElementTextContent(KEYWORD_CREATED, namespaceDcTerms, propsPart.getCreatedProperty(),
propsPart.getCreatedPropertyString(), "dcterms:W3CDTF");
}
/**
* Add creator property element if needed.
*/
private void addCreator() {
if (!propsPart.getCreatorProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_CREATOR, namespaceDC));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_CREATOR, namespaceDC));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getCreatorProperty().getValue());
setElementTextContent(KEYWORD_CREATOR, namespaceDC, propsPart.getCreatorProperty());
}
/**
* Add description property element if needed.
*/
private void addDescription() {
if (!propsPart.getDescriptionProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_DESCRIPTION, namespaceDC));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_DESCRIPTION, namespaceDC));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getDescriptionProperty().getValue());
setElementTextContent(KEYWORD_DESCRIPTION, namespaceDC, propsPart.getDescriptionProperty());
}
/**
* Add identifier property element if needed.
*/
private void addIdentifier() {
if (!propsPart.getIdentifierProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_IDENTIFIER, namespaceDC));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_IDENTIFIER, namespaceDC));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getIdentifierProperty().getValue());
setElementTextContent(KEYWORD_IDENTIFIER, namespaceDC, propsPart.getIdentifierProperty());
}
/**
/**
* Add keywords property element if needed.
*/
private void addKeywords() {
if (!propsPart.getKeywordsProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_KEYWORDS, namespaceCoreProperties));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_KEYWORDS, namespaceCoreProperties));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getKeywordsProperty().getValue());
setElementTextContent(KEYWORD_KEYWORDS, namespaceCoreProperties, propsPart.getKeywordsProperty());
}
/**
* Add language property element if needed.
*/
private void addLanguage() {
if (!propsPart.getLanguageProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_LANGUAGE, namespaceDC));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_LANGUAGE, namespaceDC));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getLanguageProperty().getValue());
setElementTextContent(KEYWORD_LANGUAGE, namespaceDC, propsPart.getLanguageProperty());
}
/**
* Add 'last modified by' property if needed.
*/
private void addLastModifiedBy() {
if (!propsPart.getLastModifiedByProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_LAST_MODIFIED_BY, namespaceCoreProperties));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement()
.addElement(
new QName(KEYWORD_LAST_MODIFIED_BY,
namespaceCoreProperties));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getLastModifiedByProperty().getValue());
setElementTextContent(KEYWORD_LAST_MODIFIED_BY, namespaceCoreProperties, propsPart.getLastModifiedByProperty());
}
/**
@ -323,111 +237,39 @@ public class PackagePropertiesMarshaller implements PartMarshaller {
*
*/
private void addLastPrinted() {
if (!propsPart.getLastPrintedProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_LAST_PRINTED, namespaceCoreProperties));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_LAST_PRINTED, namespaceCoreProperties));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getLastPrintedPropertyString());
setElementTextContent(KEYWORD_LAST_PRINTED, namespaceCoreProperties, propsPart.getLastPrintedProperty(), propsPart.getLastPrintedPropertyString());
}
/**
* Add modified property element if needed.
*/
private void addModified() {
if (!propsPart.getModifiedProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_MODIFIED, namespaceDcTerms));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_MODIFIED, namespaceDcTerms));
} else {
elem.clearContent();// clear the old value
}
elem.addAttribute(new QName("type", namespaceXSI), "dcterms:W3CDTF");
elem.addText(propsPart.getModifiedPropertyString());
}
setElementTextContent(KEYWORD_MODIFIED, namespaceDcTerms, propsPart.getModifiedProperty(),
propsPart.getModifiedPropertyString(), "dcterms:W3CDTF");
}
/**
* Add revision property if needed.
*/
private void addRevision() {
if (!propsPart.getRevisionProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_REVISION, namespaceCoreProperties));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_REVISION, namespaceCoreProperties));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getRevisionProperty().getValue());
setElementTextContent(KEYWORD_REVISION, namespaceCoreProperties, propsPart.getRevisionProperty());
}
/**
* Add subject property if needed.
*/
private void addSubject() {
if (!propsPart.getSubjectProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_SUBJECT, namespaceDC));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_SUBJECT, namespaceDC));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getSubjectProperty().getValue());
setElementTextContent(KEYWORD_SUBJECT, namespaceDC, propsPart.getSubjectProperty());
}
/**
* Add title property if needed.
*/
private void addTitle() {
if (!propsPart.getTitleProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_TITLE, namespaceDC));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_TITLE, namespaceDC));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getTitleProperty().getValue());
setElementTextContent(KEYWORD_TITLE, namespaceDC, propsPart.getTitleProperty());
}
private void addVersion() {
if (!propsPart.getVersionProperty().hasValue())
return;
Element elem = xmlDoc.getRootElement().element(
new QName(KEYWORD_VERSION, namespaceCoreProperties));
if (elem == null) {
// missing, we add it
elem = xmlDoc.getRootElement().addElement(
new QName(KEYWORD_VERSION, namespaceCoreProperties));
} else {
elem.clearContent();// clear the old value
}
elem.addText(propsPart.getVersionProperty().getValue());
setElementTextContent(KEYWORD_VERSION, namespaceCoreProperties, propsPart.getVersionProperty());
}
}

View File

@ -24,11 +24,6 @@ import java.net.URI;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.PackageNamespaces;
import org.apache.poi.openxml4j.opc.PackagePart;
@ -40,8 +35,11 @@ import org.apache.poi.openxml4j.opc.StreamHelper;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.openxml4j.opc.internal.PartMarshaller;
import org.apache.poi.openxml4j.opc.internal.ZipHelper;
import org.apache.poi.util.DocumentHelper;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Zip part marshaller. This marshaller is use to save any part in a zip stream.
@ -122,9 +120,8 @@ public final class ZipPartMarshaller implements PartMarshaller {
Document xmlOutDoc = DocumentHelper.createDocument();
// make something like <Relationships
// xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
Namespace dfNs = Namespace.get("", PackageNamespaces.RELATIONSHIPS);
Element root = xmlOutDoc.addElement(new QName(
PackageRelationship.RELATIONSHIPS_TAG_NAME, dfNs));
Element root = xmlOutDoc.createElementNS(PackageNamespaces.RELATIONSHIPS, PackageRelationship.RELATIONSHIPS_TAG_NAME);
xmlOutDoc.appendChild(root);
// <Relationship
// TargetMode="External"
@ -137,16 +134,14 @@ public final class ZipPartMarshaller implements PartMarshaller {
for (PackageRelationship rel : rels) {
// the relationship element
Element relElem = root
.addElement(PackageRelationship.RELATIONSHIP_TAG_NAME);
Element relElem = xmlOutDoc.createElement(PackageRelationship.RELATIONSHIP_TAG_NAME);
root.appendChild(relElem);
// the relationship ID
relElem.addAttribute(PackageRelationship.ID_ATTRIBUTE_NAME, rel
.getId());
relElem.setAttribute(PackageRelationship.ID_ATTRIBUTE_NAME, rel.getId());
// the relationship Type
relElem.addAttribute(PackageRelationship.TYPE_ATTRIBUTE_NAME, rel
.getRelationshipType());
relElem.setAttribute(PackageRelationship.TYPE_ATTRIBUTE_NAME, rel.getRelationshipType());
// the relationship Target
String targetValue;
@ -157,16 +152,13 @@ public final class ZipPartMarshaller implements PartMarshaller {
targetValue = uri.toString();
// add TargetMode attribute (as it is external link external)
relElem.addAttribute(
PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME,
"External");
relElem.setAttribute(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME, "External");
} else {
URI targetURI = rel.getTargetURI();
targetValue = PackagingURIHelper.relativizeURI(
sourcePartURI, targetURI, true).toString();
}
relElem.addAttribute(PackageRelationship.TARGET_ATTRIBUTE_NAME,
targetValue);
relElem.setAttribute(PackageRelationship.TARGET_ATTRIBUTE_NAME, targetValue);
}
xmlOutDoc.normalize();

View File

@ -19,10 +19,10 @@ package org.apache.poi.openxml4j.opc.internal.unmarshallers;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import javax.xml.XMLConstants;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.PackageNamespaces;
import org.apache.poi.openxml4j.opc.PackagePart;
@ -32,12 +32,12 @@ import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart;
import org.apache.poi.openxml4j.opc.internal.PartUnmarshaller;
import org.apache.poi.openxml4j.opc.internal.ZipHelper;
import org.apache.poi.util.SAXHelper;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Package properties unmarshaller.
@ -46,21 +46,6 @@ import org.dom4j.QName;
*/
public final class PackagePropertiesUnmarshaller implements PartUnmarshaller {
private final static Namespace namespaceDC = new Namespace("dc",
PackageProperties.NAMESPACE_DC);
private final static Namespace namespaceCP = new Namespace("cp",
PackageNamespaces.CORE_PROPERTIES);
private final static Namespace namespaceDcTerms = new Namespace("dcterms",
PackageProperties.NAMESPACE_DCTERMS);
private final static Namespace namespaceXML = new Namespace("xml",
"http://www.w3.org/XML/1998/namespace");
private final static Namespace namespaceXSI = new Namespace("xsi",
"http://www.w3.org/2001/XMLSchema-instance");
protected static final String KEYWORD_CATEGORY = "category";
protected static final String KEYWORD_CONTENT_STATUS = "contentStatus";
@ -125,15 +110,15 @@ public final class PackagePropertiesUnmarshaller implements PartUnmarshaller {
/* Check OPC compliance */
// Rule M4.2, M4.3, M4.4 and M4.5/
checkElementForOPCCompliance(xmlDoc.getRootElement());
checkElementForOPCCompliance(xmlDoc.getDocumentElement());
/* End OPC compliance */
} catch (DocumentException e) {
throw new IOException(e.getMessage());
}
} catch (SAXException e) {
throw new IOException(e.getMessage());
}
coreProps.setCategoryProperty(loadCategory(xmlDoc));
coreProps.setCategoryProperty(loadCategory(xmlDoc));
coreProps.setContentStatusProperty(loadContentStatus(xmlDoc));
coreProps.setContentTypeProperty(loadContentType(xmlDoc));
coreProps.setCreatedProperty(loadCreated(xmlDoc));
@ -153,148 +138,76 @@ public final class PackagePropertiesUnmarshaller implements PartUnmarshaller {
return coreProps;
}
private String readElement(Document xmlDoc, String localName, String namespaceURI) {
Element el = (Element)xmlDoc.getDocumentElement().getElementsByTagNameNS(namespaceURI, localName).item(0);
if (el == null) {
return null;
}
return el.getTextContent();
}
private String loadCategory(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_CATEGORY, namespaceCP));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_CATEGORY, PackageNamespaces.CORE_PROPERTIES);
}
private String loadContentStatus(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_CONTENT_STATUS, namespaceCP));
if (el == null) {
return null;
}
return el.getStringValue();
private String loadContentStatus(Document xmlDoc) {
return readElement(xmlDoc, KEYWORD_CONTENT_STATUS, PackageNamespaces.CORE_PROPERTIES);
}
private String loadContentType(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_CONTENT_TYPE, namespaceCP));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_CONTENT_TYPE, PackageNamespaces.CORE_PROPERTIES);
}
private String loadCreated(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_CREATED, namespaceDcTerms));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_CREATED, PackageProperties.NAMESPACE_DCTERMS);
}
private String loadCreator(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_CREATOR, namespaceDC));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_CREATOR, PackageProperties.NAMESPACE_DC);
}
private String loadDescription(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_DESCRIPTION, namespaceDC));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_DESCRIPTION, PackageProperties.NAMESPACE_DC);
}
private String loadIdentifier(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_IDENTIFIER, namespaceDC));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_IDENTIFIER, PackageProperties.NAMESPACE_DC);
}
private String loadKeywords(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_KEYWORDS, namespaceCP));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_KEYWORDS, PackageNamespaces.CORE_PROPERTIES);
}
private String loadLanguage(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_LANGUAGE, namespaceDC));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_LANGUAGE, PackageProperties.NAMESPACE_DC);
}
private String loadLastModifiedBy(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_LAST_MODIFIED_BY, namespaceCP));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_LAST_MODIFIED_BY, PackageNamespaces.CORE_PROPERTIES);
}
private String loadLastPrinted(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_LAST_PRINTED, namespaceCP));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_LAST_PRINTED, PackageNamespaces.CORE_PROPERTIES);
}
private String loadModified(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_MODIFIED, namespaceDcTerms));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_MODIFIED, PackageProperties.NAMESPACE_DCTERMS);
}
private String loadRevision(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_REVISION, namespaceCP));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_REVISION, PackageNamespaces.CORE_PROPERTIES);
}
private String loadSubject(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_SUBJECT, namespaceDC));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_SUBJECT, PackageProperties.NAMESPACE_DC);
}
private String loadTitle(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_TITLE, namespaceDC));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_TITLE, PackageProperties.NAMESPACE_DC);
}
private String loadVersion(Document xmlDoc) {
Element el = xmlDoc.getRootElement().element(
new QName(KEYWORD_VERSION, namespaceCP));
if (el == null) {
return null;
}
return el.getStringValue();
return readElement(xmlDoc, KEYWORD_VERSION, PackageNamespaces.CORE_PROPERTIES);
}
/* OPC Compliance methods */
@ -325,60 +238,56 @@ public final class PackagePropertiesUnmarshaller implements PartUnmarshaller {
public void checkElementForOPCCompliance(Element el)
throws InvalidFormatException {
// Check the current element
@SuppressWarnings("unchecked")
List<Namespace> declaredNamespaces = el.declaredNamespaces();
Iterator<Namespace> itNS = declaredNamespaces.iterator();
while (itNS.hasNext()) {
Namespace ns = itNS.next();
NamedNodeMap namedNodeMap = el.getAttributes();
int namedNodeCount = namedNodeMap.getLength();
for (int i = 0; i < namedNodeCount; i++) {
Attr attr = (Attr)namedNodeMap.item(0);
// Rule M4.2
if (ns.getURI().equals(PackageNamespaces.MARKUP_COMPATIBILITY))
throw new InvalidFormatException(
"OPC Compliance error [M4.2]: A format consumer shall consider the use of the Markup Compatibility namespace to be an error.");
}
if (attr.getNamespaceURI().equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
// Rule M4.2
if (attr.getValue().equals(PackageNamespaces.MARKUP_COMPATIBILITY))
throw new InvalidFormatException(
"OPC Compliance error [M4.2]: A format consumer shall consider the use of the Markup Compatibility namespace to be an error.");
}
}
// Rule M4.3
if (el.getNamespace().getURI().equals(
PackageProperties.NAMESPACE_DCTERMS)
&& !(el.getName().equals(KEYWORD_CREATED) || el.getName()
.equals(KEYWORD_MODIFIED)))
throw new InvalidFormatException(
"OPC Compliance error [M4.3]: Producers shall not create a document element that contains refinements to the Dublin Core elements, except for the two specified in the schema: <dcterms:created> and <dcterms:modified> Consumers shall consider a document element that violates this constraint to be an error.");
String elName = el.getLocalName();
if (el.getNamespaceURI().equals(PackageProperties.NAMESPACE_DCTERMS))
if (!(elName.equals(KEYWORD_CREATED) || elName.equals(KEYWORD_MODIFIED)))
throw new InvalidFormatException(
"OPC Compliance error [M4.3]: Producers shall not create a document element that contains refinements to the Dublin Core elements, except for the two specified in the schema: <dcterms:created> and <dcterms:modified> Consumers shall consider a document element that violates this constraint to be an error.");
// Rule M4.4
if (el.attribute(new QName("lang", namespaceXML)) != null)
if (el.getAttributeNodeNS(XMLConstants.XML_NS_URI, "lang") != null)
throw new InvalidFormatException(
"OPC Compliance error [M4.4]: Producers shall not create a document element that contains the xml:lang attribute. Consumers shall consider a document element that violates this constraint to be an error.");
// Rule M4.5
if (el.getNamespace().getURI().equals(
PackageProperties.NAMESPACE_DCTERMS)) {
if (el.getNamespaceURI().equals(PackageProperties.NAMESPACE_DCTERMS)) {
// DCTerms namespace only use with 'created' and 'modified' elements
String elName = el.getName();
if (!(elName.equals(KEYWORD_CREATED) || elName
.equals(KEYWORD_MODIFIED)))
if (!(elName.equals(KEYWORD_CREATED) || elName.equals(KEYWORD_MODIFIED)))
throw new InvalidFormatException("Namespace error : " + elName
+ " shouldn't have the following naemspace -> "
+ PackageProperties.NAMESPACE_DCTERMS);
// Check for the 'xsi:type' attribute
Attribute typeAtt = el.attribute(new QName("type", namespaceXSI));
Attr typeAtt = el.getAttributeNodeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type");
if (typeAtt == null)
throw new InvalidFormatException("The element '" + elName
+ "' must have the '" + namespaceXSI.getPrefix()
+ ":type' attribute present !");
+ "' must have the 'xsi:type' attribute present !");
// Check for the attribute value => 'dcterms:W3CDTF'
if (!typeAtt.getValue().equals("dcterms:W3CDTF"))
throw new InvalidFormatException("The element '" + elName
+ "' must have the '" + namespaceXSI.getPrefix()
+ ":type' attribute with the value 'dcterms:W3CDTF' !");
+ "' must have the 'xsi:type' attribute with the value 'dcterms:W3CDTF' !");
}
// Check its children
@SuppressWarnings("unchecked")
Iterator<Element> itChildren = el.elementIterator();
while (itChildren.hasNext())
checkElementForOPCCompliance(itChildren.next());
NodeList childElements = el.getElementsByTagName("*");
int childElementCount = childElements.getLength();
for (int i = 0; i < childElementCount; i++)
checkElementForOPCCompliance((Element)childElements.item(i));
}
}

View File

@ -0,0 +1,60 @@
/* ====================================================================
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.poi.util;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.events.Namespace;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class DocumentHelper {
private static final DocumentBuilder newDocumentBuilder;
static {
try {
newDocumentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new IllegalStateException("cannot create a DocumentBuilder", e);
}
}
public static synchronized Document createDocument() {
return newDocumentBuilder.newDocument();
}
/**
* Adds a namespace declaration attribute to the given element.
*/
public static void addNamespaceDeclaration(Element element, String namespacePrefix, String namespaceURI) {
element.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
XMLConstants.XMLNS_ATTRIBUTE + ':' + namespacePrefix,
namespaceURI);
}
/**
* Adds a namespace declaration attribute to the given element.
*/
public static void addNamespaceDeclaration(Element element, Namespace namespace) {
addNamespaceDeclaration(element, namespace.getPrefix(), namespace.getNamespaceURI());
}
}

View File

@ -23,10 +23,11 @@ import java.io.StringReader;
import java.lang.reflect.Method;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.w3c.dom.Document;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@ -37,31 +38,44 @@ import org.xml.sax.SAXException;
*/
public final class SAXHelper {
private static POILogger logger = POILogFactory.getLogger(SAXHelper.class);
/**
* Creates a new SAX Reader, with sensible defaults
*/
public static SAXReader getSAXReader() {
SAXReader xmlReader = new SAXReader();
xmlReader.setValidation(false);
xmlReader.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
return new InputSource(new StringReader(""));
}
});
trySetSAXFeature(xmlReader, XMLConstants.FEATURE_SECURE_PROCESSING, true);
trySetXercesSecurityManager(xmlReader);
return xmlReader;
private static final EntityResolver IGNORING_ENTITY_RESOLVER = new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
return new InputSource(new StringReader(""));
}
};
private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
static {
documentBuilderFactory.setNamespaceAware(true);
documentBuilderFactory.setValidating(false);
trySetSAXFeature(documentBuilderFactory, XMLConstants.FEATURE_SECURE_PROCESSING, true);
trySetXercesSecurityManager(documentBuilderFactory);
}
private static void trySetSAXFeature(SAXReader xmlReader, String feature, boolean enabled) {
/**
* Creates a new document builder, with sensible defaults
*/
public static synchronized DocumentBuilder getDocumentBuilder() {
try {
xmlReader.setFeature(feature, enabled);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
documentBuilder.setEntityResolver(IGNORING_ENTITY_RESOLVER);
return documentBuilder;
} catch (ParserConfigurationException e) {
throw new IllegalStateException("cannot create a DocumentBuilder", e);
}
}
private static void trySetSAXFeature(DocumentBuilderFactory documentBuilderFactory, String feature, boolean enabled) {
try {
documentBuilderFactory.setFeature(feature, enabled);
} catch (Exception e) {
logger.log(POILogger.INFO, "SAX Feature unsupported", feature, e);
}
}
private static void trySetXercesSecurityManager(SAXReader xmlReader) {
private static void trySetXercesSecurityManager(DocumentBuilderFactory documentBuilderFactory) {
// Try built-in JVM one first, standalone if not
for (String securityManagerClassName : new String[] {
"com.sun.org.apache.xerces.internal.util.SecurityManager",
@ -71,7 +85,7 @@ public final class SAXHelper {
Object mgr = Class.forName(securityManagerClassName).newInstance();
Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE);
setLimit.invoke(mgr, 4096);
xmlReader.setProperty("http://apache.org/xml/properties/security-manager", mgr);
documentBuilderFactory.setAttribute("http://apache.org/xml/properties/security-manager", mgr);
// Stop once one can be setup without error
return;
} catch (Exception e) {
@ -86,7 +100,7 @@ public final class SAXHelper {
* @param inp Stream to read the XML data from
* @return the SAX processed Document
*/
public static Document readSAXDocument(InputStream inp) throws DocumentException {
return getSAXReader().read(inp);
public static Document readSAXDocument(InputStream inp) throws IOException, SAXException {
return getDocumentBuilder().parse(inp);
}
}

View File

@ -27,7 +27,6 @@ import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;
import java.util.regex.Pattern;
@ -40,15 +39,14 @@ import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
import org.apache.poi.openxml4j.opc.internal.ContentTypeManager;
import org.apache.poi.openxml4j.opc.internal.FileHelper;
import org.apache.poi.openxml4j.opc.internal.PackagePropertiesPart;
import org.apache.poi.util.DocumentHelper;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.SAXHelper;
import org.apache.poi.util.TempFile;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public final class TestPackage extends TestCase {
private static final POILogger logger = POILogFactory.getLogger(TestPackage.class);
@ -127,18 +125,17 @@ public final class TestPackage extends TestCase {
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml");
Document doc = DocumentHelper.createDocument();
Namespace nsWordprocessinML = new Namespace("w",
"http://schemas.openxmlformats.org/wordprocessingml/2006/main");
Element elDocument = doc.addElement(new QName("document",
nsWordprocessinML));
Element elBody = elDocument.addElement(new QName("body",
nsWordprocessinML));
Element elParagraph = elBody.addElement(new QName("p",
nsWordprocessinML));
Element elRun = elParagraph
.addElement(new QName("r", nsWordprocessinML));
Element elText = elRun.addElement(new QName("t", nsWordprocessinML));
elText.setText("Hello Open XML !");
Element elDocument = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:document");
doc.appendChild(elDocument);
Element elBody = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:body");
elDocument.appendChild(elBody);
Element elParagraph = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:p");
elBody.appendChild(elParagraph);
Element elRun = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:r");
elParagraph.appendChild(elRun);
Element elText = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:t");
elRun.appendChild(elText);
elText.setTextContent("Hello Open XML !");
StreamHelper.saveXmlInStream(doc, corePart.getOutputStream());
pkg.close();
@ -223,15 +220,13 @@ public final class TestPackage extends TestCase {
Document xmlRelationshipsDoc = SAXHelper.readSAXDocument(relPart.getInputStream());
Element root = xmlRelationshipsDoc.getRootElement();
for (Iterator i = root
.elementIterator(PackageRelationship.RELATIONSHIP_TAG_NAME); i
.hasNext();) {
Element element = (Element) i.next();
String value = element.attribute(
PackageRelationship.TARGET_ATTRIBUTE_NAME)
.getValue();
assertTrue("Root target must not start with a leadng slash ('/'): " + value, value.charAt(0) != '/');
Element root = xmlRelationshipsDoc.getDocumentElement();
NodeList nodeList = root.getElementsByTagName(PackageRelationship.RELATIONSHIP_TAG_NAME);
int nodeCount = nodeList.getLength();
for (int i = 0; i < nodeCount; i++) {
Element element = (Element) nodeList.item(i);
String value = element.getAttribute(PackageRelationship.TARGET_ATTRIBUTE_NAME);
assertTrue("Root target must not start with a leading slash ('/'): " + value, value.charAt(0) != '/');
}
}
@ -268,18 +263,17 @@ public final class TestPackage extends TestCase {
// Create a content
Document doc = DocumentHelper.createDocument();
Namespace nsWordprocessinML = new Namespace("w",
"http://schemas.openxmlformats.org/wordprocessingml/2006/main");
Element elDocument = doc.addElement(new QName("document",
nsWordprocessinML));
Element elBody = elDocument.addElement(new QName("body",
nsWordprocessinML));
Element elParagraph = elBody.addElement(new QName("p",
nsWordprocessinML));
Element elRun = elParagraph
.addElement(new QName("r", nsWordprocessinML));
Element elText = elRun.addElement(new QName("t", nsWordprocessinML));
elText.setText("Hello Open XML !");
Element elDocument = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:document");
doc.appendChild(elDocument);
Element elBody = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:body");
elDocument.appendChild(elBody);
Element elParagraph = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:p");
elBody.appendChild(elParagraph);
Element elRun = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:r");
elParagraph.appendChild(elRun);
Element elText = doc.createElementNS("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:t");
elRun.appendChild(elText);
elText.setTextContent("Hello Open XML !");
StreamHelper.saveXmlInStream(doc, corePart.getOutputStream());