123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /* ====================================================================
- 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;
-
- import java.io.IOException;
- import java.util.*;
- import java.net.URI;
-
- import org.apache.xmlbeans.XmlOptions;
- import org.apache.poi.util.POILogger;
- import org.apache.poi.util.POILogFactory;
- import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
- import org.apache.poi.openxml4j.opc.*;
-
- /**
- * Represents an entry of a OOXML package.
- *
- * <p>
- * Each POIXMLDocumentPart keeps a reference to the underlying a {@link org.apache.poi.openxml4j.opc.PackagePart}.
- * </p>
- *
- * @author Yegor Kozlov
- */
- public class POIXMLDocumentPart {
- private static POILogger logger = POILogFactory.getLogger(POIXMLDocumentPart.class);
-
- public static final XmlOptions DEFAULT_XML_OPTIONS;
- static {
- DEFAULT_XML_OPTIONS = new XmlOptions();
- DEFAULT_XML_OPTIONS.setSaveOuter();
- DEFAULT_XML_OPTIONS.setUseDefaultNamespace();
- DEFAULT_XML_OPTIONS.setSaveAggressiveNamespaces();
- }
-
- private PackagePart packagePart;
- private PackageRelationship packageRel;
- private POIXMLDocumentPart parent;
- private List<POIXMLDocumentPart> relations;
-
- /**
- * Construct POIXMLDocumentPart representing a "core document" package part.
- */
- public POIXMLDocumentPart(OPCPackage pkg) {
- PackageRelationship coreRel = pkg.getRelationshipsByType(
- PackageRelationshipTypes.CORE_DOCUMENT).getRelationship(0);
-
- this.relations = new LinkedList<POIXMLDocumentPart>();
- this.packagePart = pkg.getPart(coreRel);
- this.packageRel = coreRel;
- }
-
- /**
- * Creates new POIXMLDocumentPart - called by client code to create new parts from scratch.
- *
- * @see #createRelationship(POIXMLRelation, POIXMLFactory, int, boolean)
- */
- public POIXMLDocumentPart(){
- this.relations = new LinkedList<POIXMLDocumentPart>();
- }
-
- /**
- * Creates an POIXMLDocumentPart representing the given package part and relationship.
- * Called by {@link #read(POIXMLFactory, java.util.Map)} when reading in an exisiting file.
- *
- * @param part - The package part that holds xml data represenring this sheet.
- * @param rel - the relationship of the given package part
- * @see #read(POIXMLFactory, java.util.Map)
- */
- public POIXMLDocumentPart(PackagePart part, PackageRelationship rel){
- this.relations = new LinkedList<POIXMLDocumentPart>();
- this.packagePart = part;
- this.packageRel = rel;
- }
-
- /**
- * Provides access to the underlying PackagePart
- *
- * @return the underlying PackagePart
- */
- public final PackagePart getPackagePart(){
- return packagePart;
- }
-
- /**
- * Provides access to the PackageRelationship that identifies this POIXMLDocumentPart
- *
- * @return the PackageRelationship that identifies this POIXMLDocumentPart
- */
- public final PackageRelationship getPackageRelationship(){
- return packageRel;
- }
-
- /**
- * Returns the list of child relations for this POIXMLDocumentPart
- *
- * @return child relations
- */
- public final List<POIXMLDocumentPart> getRelations(){
- return relations;
- }
-
- /**
- * Add a new child POIXMLDocumentPart
- *
- * @param part the child to add
- */
- protected final void addRelation(POIXMLDocumentPart part){
- relations.add(part);
- }
-
- /**
- * Remove the specified part in this package.
- */
- public final void removeRelation(POIXMLDocumentPart part){
- getPackagePart().removeRelationship(part.getPackageRelationship().getId());
- getPackagePart().getPackage().removePart(part.getPackagePart());
- relations.remove(part);
- }
-
- /**
- * Returns the parent POIXMLDocumentPart. All parts except root have not-null parent.
- *
- * @return the parent POIXMLDocumentPart or <code>null</code> for the root element.
- */
- public final POIXMLDocumentPart getParent(){
- return parent;
- }
-
- @Override
- public String toString(){
- return packagePart == null ? null : packagePart.toString();
- }
-
- /**
- * Save the content in the underlying package part.
- * Default implementation is empty meaning that the package part is left unmodified.
- *
- * Sub-classes should override and add logic to marshal the "model" into Ooxml4J.
- *
- * For example, the code saving a generic XML entry may look as follows:
- * <pre><code>
- * protected void commit() throws IOException {
- * PackagePart part = getPackagePart();
- * OutputStream out = part.getOutputStream();
- * XmlObject bean = getXmlBean(); //the "model" which holds changes in memory
- * bean.save(out, DEFAULT_XML_OPTIONS);
- * out.close();
- * }
- * </code></pre>
- *
- */
- protected void commit() throws IOException {
-
- }
-
- /**
- * Save changes in the underlying OOXML package.
- * Recursively fires {@link #commit()} for each package part
- *
- * @param alreadySaved context set containing already visited nodes
- */
- protected final void onSave(Set<PackagePart> alreadySaved) throws IOException{
- commit();
- alreadySaved.add(this.getPackagePart());
- for(POIXMLDocumentPart p : relations){
- if (!alreadySaved.contains(p.getPackagePart())) {
- p.onSave(alreadySaved);
- }
- }
- }
-
- /**
- * Create a new child POIXMLDocumentPart
- *
- * @param descriptor the part descriptor
- * @param factory the factory that will create an instance of the requested relation
- * @return the created child POIXMLDocumentPart
- */
- public final POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory){
- return createRelationship(descriptor, factory, -1, false);
- }
-
- public final POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory, int idx){
- return createRelationship(descriptor, factory, idx, false);
- }
-
- /**
- * Create a new child POIXMLDocumentPart
- *
- * @param descriptor the part descriptor
- * @param factory the factory that will create an instance of the requested relation
- * @param idx part number
- * @param noRelation if true, then no relationship is added.
- * @return the created child POIXMLDocumentPart
- */
- protected final POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory, int idx, boolean noRelation){
- try {
- PackagePartName ppName = PackagingURIHelper.createPartName(descriptor.getFileName(idx));
- PackageRelationship rel = null;
- if(!noRelation) rel = packagePart.addRelationship(ppName, TargetMode.INTERNAL, descriptor.getRelation());
- PackagePart part = packagePart.getPackage().createPart(ppName, descriptor.getContentType());
- POIXMLDocumentPart doc = factory.newDocumentPart(descriptor);
- doc.packageRel = rel;
- doc.packagePart = part;
- doc.parent = this;
- addRelation(doc);
- return doc;
- } catch (Exception e){
- throw new POIXMLException(e);
- }
- }
-
- /**
- * Iterate through the underlying PackagePart and create child POIXMLFactory instances
- * using the specified factory
- *
- * @param factory the factory object that creates POIXMLFactory instances
- * @param context context map containing already visited noted keyed by targetURI
- */
- protected void read(POIXMLFactory factory, Map<PackagePart, POIXMLDocumentPart> context) throws OpenXML4JException {
- PackageRelationshipCollection rels = packagePart.getRelationships();
- for (PackageRelationship rel : rels) {
- if(rel.getTargetMode() == TargetMode.INTERNAL){
- URI uri = rel.getTargetURI();
-
- PackagePart p;
- if(uri.getRawFragment() != null) {
- /*
- * For internal references (e.g. '#Sheet1!A1') the package part is null
- */
- p = null;
- } else {
- PackagePartName relName = PackagingURIHelper.createPartName(uri);
- p = packagePart.getPackage().getPart(relName);
- if(p == null) {
- logger.log(POILogger.ERROR, "Skipped invalid entry " + rel.getTargetURI());
- continue;
- }
- }
-
- if (!context.containsKey(p)) {
- POIXMLDocumentPart childPart = factory.createDocumentPart(rel, p);
- childPart.parent = this;
- addRelation(childPart);
- if(p != null){
- context.put(p, childPart);
- if(p.hasRelationships()) childPart.read(factory, context);
- }
- }
- else {
- addRelation(context.get(p));
- }
- }
- }
- }
-
- /**
- * Fired when a new package part is created
- */
- protected void onDocumentCreate() throws IOException {
-
- }
-
- /**
- * Fired when a package part is read
- */
- protected void onDocumentRead() throws IOException{
-
- }
-
- }
|