git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1873514 13f79535-47bb-0310-9956-ffa450edef68tags/REL_4_1_2
@@ -19,15 +19,21 @@ | |||
package org.apache.poi.xslf.model; | |||
import javax.xml.namespace.QName; | |||
import javax.xml.stream.XMLStreamReader; | |||
import org.apache.poi.xslf.usermodel.XSLFShape; | |||
import org.apache.xmlbeans.XmlObject; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties; | |||
/** | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public abstract class ParagraphPropertyFetcher<T> extends PropertyFetcher<T> { | |||
static final String PML_NS = "http://schemas.openxmlformats.org/presentationml/2006/main"; | |||
static final String DML_NS = "http://schemas.openxmlformats.org/drawingml/2006/main"; | |||
private static final QName[] TX_BODY = { new QName(PML_NS, "txBody") }; | |||
private static final QName[] LST_STYLE = { new QName(DML_NS, "lstStyle") }; | |||
int _level; | |||
public ParagraphPropertyFetcher(int level) { | |||
@@ -35,17 +41,20 @@ public abstract class ParagraphPropertyFetcher<T> extends PropertyFetcher<T> { | |||
} | |||
public boolean fetch(XSLFShape shape) { | |||
XmlObject[] o = shape.getXmlObject().selectPath( | |||
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " + | |||
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " + | |||
".//p:txBody/a:lstStyle/a:lvl" + (_level + 1) + "pPr" | |||
); | |||
if (o.length == 1) { | |||
CTTextParagraphProperties props = (CTTextParagraphProperties) o[0]; | |||
return fetch(props); | |||
QName[] lvlProp = { new QName(DML_NS, "lvl" + (_level + 1) + "pPr") }; | |||
CTTextParagraphProperties props = null; | |||
try { | |||
props = shape.selectProperty( | |||
CTTextParagraphProperties.class, ParagraphPropertyFetcher::parse, TX_BODY, LST_STYLE, lvlProp); | |||
return (props != null) && fetch(props); | |||
} catch (XmlException e) { | |||
return false; | |||
} | |||
return false; | |||
} | |||
private static CTTextParagraphProperties parse(XMLStreamReader reader) throws XmlException { | |||
CTTextParagraph para = CTTextParagraph.Factory.parse(reader); | |||
return (para != null && para.isSetPPr()) ? para.getPPr() : null; | |||
} | |||
public abstract boolean fetch(CTTextParagraphProperties props); |
@@ -19,32 +19,35 @@ | |||
package org.apache.poi.xslf.model; | |||
import static org.apache.poi.xslf.model.ParagraphPropertyFetcher.DML_NS; | |||
import static org.apache.poi.xslf.model.ParagraphPropertyFetcher.PML_NS; | |||
import javax.xml.namespace.QName; | |||
import javax.xml.stream.XMLStreamReader; | |||
import org.apache.poi.xslf.usermodel.XSLFShape; | |||
import org.apache.xmlbeans.XmlObject; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties; | |||
/** | |||
* Created by IntelliJ IDEA. | |||
* User: yegor | |||
* Date: Oct 21, 2011 | |||
* Time: 1:18:52 PM | |||
* To change this template use File | Settings | File Templates. | |||
*/ | |||
public abstract class TextBodyPropertyFetcher<T> extends PropertyFetcher<T> { | |||
private static final QName[] TX_BODY = { new QName(PML_NS, "txBody") }; | |||
private static final QName[] BODY_PR = { new QName(DML_NS, "bodyPr") }; | |||
public boolean fetch(XSLFShape shape) { | |||
XmlObject[] o = shape.getXmlObject().selectPath( | |||
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " + | |||
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " + | |||
".//p:txBody/a:bodyPr" | |||
); | |||
if (o.length == 1) { | |||
CTTextBodyProperties props = (CTTextBodyProperties) o[0]; | |||
return fetch(props); | |||
CTTextBodyProperties props = null; | |||
try { | |||
props = shape.selectProperty( | |||
CTTextBodyProperties.class, TextBodyPropertyFetcher::parse, TX_BODY, BODY_PR); | |||
return (props != null) && fetch(props); | |||
} catch (XmlException e) { | |||
return false; | |||
} | |||
} | |||
return false; | |||
private static CTTextBodyProperties parse(XMLStreamReader reader) throws XmlException { | |||
CTTextBody body = CTTextBody.Factory.parse(reader); | |||
return (body != null) ? body.getBodyPr() : null; | |||
} | |||
public abstract boolean fetch(CTTextBodyProperties props); |
@@ -25,10 +25,11 @@ import java.io.IOException; | |||
import java.io.OutputStream; | |||
import javax.xml.namespace.QName; | |||
import javax.xml.stream.XMLStreamReader; | |||
import org.apache.poi.hpsf.ClassID; | |||
import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart; | |||
import org.apache.poi.ooxml.POIXMLException; | |||
import org.apache.poi.hpsf.ClassID; | |||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; | |||
import org.apache.poi.openxml4j.opc.OPCPackage; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
@@ -42,8 +43,6 @@ import org.apache.poi.sl.usermodel.ObjectShape; | |||
import org.apache.poi.util.Internal; | |||
import org.apache.xmlbeans.XmlCursor; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.apache.xmlbeans.XmlObject; | |||
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData; | |||
@@ -63,6 +62,10 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPictureNonVisual; | |||
public class XSLFObjectShape extends XSLFGraphicFrame implements ObjectShape<XSLFShape,XSLFTextParagraph> { | |||
/* package */ static final String OLE_URI = "http://schemas.openxmlformats.org/presentationml/2006/ole"; | |||
private static final QName[] GRAPHIC = { new QName(DML_NS, "graphic") }; | |||
private static final QName[] GRAPHIC_DATA = { new QName(DML_NS, "graphicData") }; | |||
private static final QName[] OLE_OBJ = { new QName(PML_NS, "oleObj") }; | |||
private static final QName[] CT_PICTURE = { new QName(PML_NS, "pic") }; | |||
private CTOleObject _oleObject; | |||
private XSLFPictureData _data; | |||
@@ -70,31 +73,13 @@ public class XSLFObjectShape extends XSLFGraphicFrame implements ObjectShape<XSL | |||
/*package*/ XSLFObjectShape(CTGraphicalObjectFrame shape, XSLFSheet sheet){ | |||
super(shape, sheet); | |||
CTGraphicalObjectData god = shape.getGraphic().getGraphicData(); | |||
XmlCursor xc = god.newCursor(); | |||
// select oleObj potentially under AlternateContent | |||
// usually the mc:Choice element will be selected first | |||
xc.selectPath("declare namespace p='"+PML_NS+"' .//p:oleObj"); | |||
try { | |||
if (!xc.toNextSelection()) { | |||
throw new IllegalStateException("p:oleObj element was not found in\n " + god); | |||
} | |||
XmlObject xo = xc.getObject(); | |||
// Pesky XmlBeans bug - see Bugzilla #49934 | |||
// it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas | |||
if (xo instanceof XmlAnyTypeImpl){ | |||
String errStr = | |||
"Schemas (*.xsb) for CTOleObject can't be loaded - usually this happens when OSGI " + | |||
"loading is used and the thread context classloader has no reference to " + | |||
"the xmlbeans classes - use POIXMLTypeLoader.setClassLoader() to set the loader, " + | |||
"e.g. with CTOleObject.class.getClassLoader()" | |||
; | |||
throw new IllegalStateException(errStr); | |||
} | |||
_oleObject = (CTOleObject)xo; | |||
} finally { | |||
xc.dispose(); | |||
_oleObject = selectProperty(CTOleObject.class, null, GRAPHIC, GRAPHIC_DATA, OLE_OBJ); | |||
} catch (XmlException e) { | |||
// ole objects should be also inside AlternateContent tags, even with ECMA 376 edition 1 | |||
throw new IllegalStateException(e); | |||
} | |||
} | |||
@@ -113,13 +98,13 @@ public class XSLFObjectShape extends XSLFGraphicFrame implements ObjectShape<XSL | |||
public String getProgId() { | |||
return (_oleObject == null) ? null : _oleObject.getProgId(); | |||
} | |||
@Override | |||
public String getFullName() { | |||
return (_oleObject == null) ? null : _oleObject.getName(); | |||
} | |||
/** | |||
* Return the data on the (internal) picture. | |||
* For an external linked picture, will return null | |||
@@ -160,19 +145,19 @@ public class XSLFObjectShape extends XSLFGraphicFrame implements ObjectShape<XSL | |||
} | |||
protected CTBlipFillProperties getBlipFill() { | |||
String xquery = | |||
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " | |||
+ ".//p:blipFill" | |||
; | |||
XmlObject xo = selectProperty(XmlObject.class, xquery); | |||
try { | |||
xo = CTPicture.Factory.parse(xo.getDomNode()); | |||
} catch (XmlException xe) { | |||
CTPicture pic = selectProperty | |||
(CTPicture.class, XSLFObjectShape::parse, GRAPHIC, GRAPHIC_DATA, OLE_OBJ, CT_PICTURE); | |||
return (pic != null) ? pic.getBlipFill() : null; | |||
} catch (XmlException e) { | |||
return null; | |||
} | |||
return ((CTPicture)xo).getBlipFill(); | |||
} | |||
private static CTPicture parse(XMLStreamReader reader) throws XmlException { | |||
CTGroupShape gs = CTGroupShape.Factory.parse(reader); | |||
return (gs.sizeOfPicArray() > 0) ? gs.getPicArray(0) : null; | |||
} | |||
@Override | |||
public OutputStream updateObjectData(final Application application, final ObjectMetaData metaData) throws IOException { |
@@ -33,6 +33,7 @@ import java.net.URI; | |||
import javax.imageio.ImageIO; | |||
import javax.xml.namespace.QName; | |||
import javax.xml.stream.XMLStreamReader; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
@@ -69,11 +70,15 @@ public class XSLFPictureShape extends XSLFSimpleShape | |||
implements PictureShape<XSLFShape,XSLFTextParagraph> { | |||
private static final POILogger LOG = POILogFactory.getLogger(XSLFPictureShape.class); | |||
private static final String DML_NS = "http://schemas.microsoft.com/office/drawing/2010/main"; | |||
private static final String SVG_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main"; | |||
private static final String MS_DML_NS = "http://schemas.microsoft.com/office/drawing/2010/main"; | |||
private static final String MS_SVG_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main"; | |||
private static final String BITMAP_URI = "{28A0092B-C50C-407E-A947-70E740481C1C}"; | |||
private static final String SVG_URI = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}"; | |||
private static final QName EMBED_TAG = new QName(CORE_PROPERTIES_ECMA376_NS, "embed", "rel"); | |||
private static final QName[] BLIP_FILL = { new QName(PML_NS, "blipFill") }; | |||
private XSLFPictureData _data; | |||
/*package*/ XSLFPictureShape(CTPicture shape, XSLFSheet sheet) { | |||
@@ -135,8 +140,8 @@ public class XSLFPictureShape extends XSLFSimpleShape | |||
public void setPlaceholder(Placeholder placeholder) { | |||
super.setPlaceholder(placeholder); | |||
} | |||
/** | |||
* For an external linked picture, return the last-seen | |||
* path to the picture. | |||
@@ -147,13 +152,13 @@ public class XSLFPictureShape extends XSLFSimpleShape | |||
// Internal picture, nothing to return | |||
return null; | |||
} | |||
String rId = getBlipLink(); | |||
if (rId == null) { | |||
// No link recorded, nothing we can do | |||
return null; | |||
} | |||
PackagePart p = getSheet().getPackagePart(); | |||
PackageRelationship rel = p.getRelationship(rId); | |||
if (rel != null) { | |||
@@ -168,25 +173,23 @@ public class XSLFPictureShape extends XSLFSimpleShape | |||
if (bfp != null) { | |||
return bfp; | |||
} | |||
String xquery = | |||
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main'; " | |||
+ "declare namespace mc='http://schemas.openxmlformats.org/markup-compatibility/2006' " | |||
+ ".//mc:Fallback/p:blipFill" | |||
; | |||
XmlObject xo = selectProperty(XmlObject.class, xquery); | |||
try { | |||
xo = CTPicture.Factory.parse(xo.getDomNode()); | |||
return selectProperty(CTBlipFillProperties.class, XSLFPictureShape::parse, BLIP_FILL); | |||
} catch (XmlException xe) { | |||
return null; | |||
} | |||
return ((CTPicture)xo).getBlipFill(); | |||
} | |||
private static CTBlipFillProperties parse(XMLStreamReader reader) throws XmlException { | |||
CTPicture pic = CTPicture.Factory.parse(reader); | |||
return (pic != null) ? pic.getBlipFill() : null; | |||
} | |||
protected CTBlip getBlip(){ | |||
return getBlipFill().getBlip(); | |||
} | |||
@SuppressWarnings("WeakerAccess") | |||
protected String getBlipLink(){ | |||
CTBlip blip = getBlip(); | |||
@@ -232,8 +235,8 @@ public class XSLFPictureShape extends XSLFSimpleShape | |||
extBitmap.setUri(BITMAP_URI); | |||
XmlCursor cur = extBitmap.newCursor(); | |||
cur.toEndToken(); | |||
cur.beginElement(new QName(DML_NS, "useLocalDpi", "a14")); | |||
cur.insertNamespace("a14", DML_NS); | |||
cur.beginElement(new QName(MS_DML_NS, "useLocalDpi", "a14")); | |||
cur.insertNamespace("a14", MS_DML_NS); | |||
cur.insertAttributeWithValue("val", "0"); | |||
cur.dispose(); | |||
} | |||
@@ -252,9 +255,9 @@ public class XSLFPictureShape extends XSLFSimpleShape | |||
svgBitmap.setUri(SVG_URI); | |||
XmlCursor cur = svgBitmap.newCursor(); | |||
cur.toEndToken(); | |||
cur.beginElement(new QName(SVG_NS, "svgBlip", "asvg")); | |||
cur.insertNamespace("asvg", SVG_NS); | |||
cur.insertAttributeWithValue(new QName(CORE_PROPERTIES_ECMA376_NS, "embed", "rel"), svgRelId); | |||
cur.beginElement(new QName(MS_SVG_NS, "svgBlip", "asvg")); | |||
cur.insertNamespace("asvg", MS_SVG_NS); | |||
cur.insertAttributeWithValue(EMBED_TAG, svgRelId); | |||
cur.dispose(); | |||
} | |||
@@ -277,8 +280,8 @@ public class XSLFPictureShape extends XSLFSimpleShape | |||
for (int i = 0; i < size; i++) { | |||
XmlCursor cur = extLst.getExtArray(i).newCursor(); | |||
try { | |||
if (cur.toChild(SVG_NS, "svgBlip")) { | |||
String svgRelId = cur.getAttributeText(new QName(CORE_PROPERTIES_ECMA376_NS, "embed")); | |||
if (cur.toChild(MS_SVG_NS, "svgBlip")) { | |||
String svgRelId = cur.getAttributeText(EMBED_TAG); | |||
return (svgRelId != null) ? (XSLFPictureData) getSheet().getRelationById(svgRelId) : null; | |||
} | |||
} finally { | |||
@@ -367,13 +370,13 @@ public class XSLFPictureShape extends XSLFSimpleShape | |||
CTOfficeArtExtensionList extLst = blip.getExtLst(); | |||
//noinspection deprecation | |||
for(CTOfficeArtExtension ext : extLst.getExtArray()){ | |||
String xpath = "declare namespace a14='"+ DML_NS +"' $this//a14:imgProps/a14:imgLayer"; | |||
String xpath = "declare namespace a14='"+ MS_DML_NS +"' $this//a14:imgProps/a14:imgLayer"; | |||
XmlObject[] obj = ext.selectPath(xpath); | |||
if(obj != null && obj.length == 1){ | |||
XmlCursor c = obj[0].newCursor(); | |||
String id = c.getAttributeText(new QName("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "embed"));//selectPath("declare namespace r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' $this//[@embed]"); | |||
String id = c.getAttributeText(EMBED_TAG); | |||
String newId = getSheet().importBlip(id, p.getSheet()); | |||
c.setAttributeText(new QName("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "embed"), newId); | |||
c.setAttributeText(EMBED_TAG, newId); | |||
c.dispose(); | |||
} | |||
} |
@@ -22,9 +22,12 @@ import static org.apache.poi.xslf.usermodel.XSLFShape.PML_NS; | |||
import java.util.function.Consumer; | |||
import java.util.function.Function; | |||
import javax.xml.namespace.QName; | |||
import org.apache.poi.sl.usermodel.MasterSheet; | |||
import org.apache.poi.sl.usermodel.Placeholder; | |||
import org.apache.poi.sl.usermodel.PlaceholderDetails; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps; | |||
import org.openxmlformats.schemas.presentationml.x2006.main.CTHeaderFooter; | |||
import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMaster; | |||
@@ -190,9 +193,24 @@ public class XSLFPlaceholderDetails implements PlaceholderDetails { | |||
return _ph; | |||
} | |||
private static final QName[] NV_CONTAINER = { | |||
new QName(PML_NS, "nvSpPr"), | |||
new QName(PML_NS, "nvCxnSpPr"), | |||
new QName(PML_NS, "nvGrpSpPr"), | |||
new QName(PML_NS, "nvPicPr"), | |||
new QName(PML_NS, "nvGraphicFramePr") | |||
}; | |||
private static final QName[] NV_PROPS = { | |||
new QName(PML_NS, "nvPr") | |||
}; | |||
private CTApplicationNonVisualDrawingProps getNvProps() { | |||
final String xquery = "declare namespace p='" + PML_NS + "' .//*/p:nvPr"; | |||
return shape.selectProperty(CTApplicationNonVisualDrawingProps.class, xquery); | |||
try { | |||
return shape.selectProperty(CTApplicationNonVisualDrawingProps.class, null, NV_CONTAINER, NV_PROPS); | |||
} catch (XmlException e) { | |||
return null; | |||
} | |||
} | |||
private CTHeaderFooter getHeaderFooter(final boolean create) { |
@@ -21,7 +21,13 @@ package org.apache.poi.xslf.usermodel; | |||
import java.awt.Graphics2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.util.Locale; | |||
import javax.xml.namespace.QName; | |||
import javax.xml.stream.XMLStreamReader; | |||
import com.microsoft.schemas.compatibility.AlternateContentDocument; | |||
import com.microsoft.schemas.compatibility.AlternateContentDocument.AlternateContent; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.sl.draw.DrawFactory; | |||
import org.apache.poi.sl.draw.DrawPaint; | |||
@@ -37,7 +43,9 @@ import org.apache.poi.util.Internal; | |||
import org.apache.poi.xslf.model.PropertyFetcher; | |||
import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties; | |||
import org.apache.xmlbeans.XmlCursor; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.apache.xmlbeans.XmlObject; | |||
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties; | |||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties; | |||
@@ -59,7 +67,36 @@ import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | |||
*/ | |||
@Beta | |||
public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { | |||
@Internal | |||
public interface ReparseFactory<T extends XmlObject> { | |||
T parse(XMLStreamReader reader) throws XmlException; | |||
} | |||
static final String DML_NS = "http://schemas.openxmlformats.org/drawingml/2006/main"; | |||
static final String PML_NS = "http://schemas.openxmlformats.org/presentationml/2006/main"; | |||
private static final String MC_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006"; | |||
private static final String MAC_DML_NS = "http://schemas.microsoft.com/office/mac/drawingml/2008/main"; | |||
private static final QName ALTERNATE_CONTENT_TAG = new QName(MC_NS, "AlternateContent"); | |||
private static final QName[] NV_CONTAINER = { | |||
new QName(PML_NS, "nvSpPr"), | |||
new QName(PML_NS, "nvCxnSpPr"), | |||
new QName(PML_NS, "nvGrpSpPr"), | |||
new QName(PML_NS, "nvPicPr"), | |||
new QName(PML_NS, "nvGraphicFramePr") | |||
}; | |||
private static final QName[] CNV_PROPS = { | |||
new QName(PML_NS, "cNvPr") | |||
}; | |||
private static final String OSGI_ERROR = | |||
"Schemas (*.xsb) for <CLASS> can't be loaded - usually this happens when OSGI " + | |||
"loading is used and the thread context classloader has no reference to " + | |||
"the xmlbeans classes - please either verify if the <XSB>.xsb is on the " + | |||
"classpath or alternatively try to use the full ooxml-schemas-x.x.jar"; | |||
private final XmlObject _shape; | |||
private final XSLFSheet _sheet; | |||
@@ -199,11 +236,14 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { | |||
} | |||
protected CTNonVisualDrawingProps getCNvPr() { | |||
if (_nvPr == null) { | |||
String xquery = "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:cNvPr"; | |||
_nvPr = selectProperty(CTNonVisualDrawingProps.class, xquery); | |||
try { | |||
if (_nvPr == null) { | |||
_nvPr = selectProperty(CTNonVisualDrawingProps.class, null, NV_CONTAINER, CNV_PROPS); | |||
} | |||
return _nvPr; | |||
} catch (XmlException e) { | |||
return null; | |||
} | |||
return _nvPr; | |||
} | |||
@SuppressWarnings("WeakerAccess") | |||
@@ -281,6 +321,160 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> { | |||
return (resultClass.isInstance(rs[0])) ? (T)rs[0] : null; | |||
} | |||
/** | |||
* Internal code - API may change any time! | |||
* <p> | |||
* The {@link #selectProperty(Class, String)} xquery method has some performance penalties, | |||
* which can be workaround by using {@link XmlCursor}. This method also takes into account | |||
* that {@code AlternateContent} tags can occur anywhere on the given path. | |||
* <p> | |||
* It returns the first element found - the search order is: | |||
* <ul> | |||
* <li>searching for a direct child</li> | |||
* <li>searching for a AlternateContent.Choice child</li> | |||
* <li>searching for a AlternateContent.Fallback child</li> | |||
* </ul> | |||
* Currently POI OOXML is based on the first edition of the ECMA 376 schema, which doesn't | |||
* allow AlternateContent tags to show up everywhere. The factory flag is | |||
* a workaround to process files based on a later edition. But it comes with the drawback: | |||
* any change on the returned XmlObject aren't saved back to the underlying document - | |||
* so it's a non updatable clone. If factory is null, a XmlException is | |||
* thrown if the AlternateContent is not allowed by the surrounding element or if the | |||
* extracted object is of the generic type XmlAnyTypeImpl. | |||
* | |||
* @param resultClass the requested result class | |||
* @param factory a factory parse method reference to allow reparsing of elements | |||
* extracted from AlternateContent elements. Usually the enclosing XmlBeans type needs to be used | |||
* to parse the stream | |||
* @param path the elements path, each array must contain at least 1 QName, | |||
* but can contain additional alternative tags | |||
* @return the xml object at the path location, or null if not found | |||
* | |||
* @throws XmlException If factory is null, a XmlException is | |||
* thrown if the AlternateContent is not allowed by the surrounding element or if the | |||
* extracted object is of the generic type XmlAnyTypeImpl. | |||
* | |||
* @since POI 4.1.2 | |||
*/ | |||
@SuppressWarnings("unchecked") | |||
@Internal | |||
public <T extends XmlObject> T selectProperty(Class<T> resultClass, ReparseFactory<T> factory, QName[]... path) | |||
throws XmlException { | |||
XmlObject xo = getXmlObject(); | |||
XmlCursor cur = xo.newCursor(); | |||
XmlCursor innerCur = null; | |||
try { | |||
innerCur = selectProperty(cur, path, 0, factory != null, false); | |||
if (innerCur == null) { | |||
return null; | |||
} | |||
// Pesky XmlBeans bug - see Bugzilla #49934 | |||
// it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas | |||
xo = innerCur.getObject(); | |||
if (xo instanceof XmlAnyTypeImpl) { | |||
String errorTxt = OSGI_ERROR | |||
.replace("<CLASS>", resultClass.getSimpleName()) | |||
.replace("<XSB>", resultClass.getSimpleName().toLowerCase(Locale.ROOT)+"*"); | |||
if (factory == null) { | |||
throw new XmlException(errorTxt); | |||
} else { | |||
xo = factory.parse(innerCur.newXMLStreamReader()); | |||
} | |||
} | |||
return (T)xo; | |||
} finally { | |||
cur.dispose(); | |||
if (innerCur != null) { | |||
innerCur.dispose(); | |||
} | |||
} | |||
} | |||
private XmlCursor selectProperty(final XmlCursor cur, final QName[][] path, final int offset, final boolean reparseAlternate, final boolean isAlternate) | |||
throws XmlException { | |||
// first try the direct children | |||
for (QName qn : path[offset]) { | |||
if (cur.toChild(qn)) { | |||
if (offset == path.length-1) { | |||
return cur; | |||
} | |||
cur.push(); | |||
XmlCursor innerCur = selectProperty(cur, path, offset+1, reparseAlternate, false); | |||
if (innerCur != null) { | |||
return innerCur; | |||
} | |||
cur.pop(); | |||
} | |||
} | |||
// if we were called inside an alternate content handling don't look for alternates again | |||
if (isAlternate || !cur.toChild(ALTERNATE_CONTENT_TAG)) { | |||
return null; | |||
} | |||
// otherwise check first the choice then the fallback content | |||
XmlObject xo = cur.getObject(); | |||
AlternateContent alterCont; | |||
if (xo instanceof AlternateContent) { | |||
alterCont = (AlternateContent)xo; | |||
} else { | |||
// Pesky XmlBeans bug - see Bugzilla #49934 | |||
// it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas | |||
if (!reparseAlternate) { | |||
throw new XmlException(OSGI_ERROR | |||
.replace("<CLASS>", "AlternateContent") | |||
.replace("<XSB>", "alternatecontentelement") | |||
); | |||
} | |||
try { | |||
AlternateContentDocument acd = AlternateContentDocument.Factory.parse(cur.newXMLStreamReader()); | |||
alterCont = acd.getAlternateContent(); | |||
} catch (XmlException e) { | |||
throw new XmlException("unable to parse AlternateContent element", e); | |||
} | |||
} | |||
final int choices = alterCont.sizeOfChoiceArray(); | |||
for (int i=0; i<choices; i++) { | |||
// TODO: check [Requires] attribute of [Choice] element, if we can handle the content | |||
AlternateContent.Choice choice = alterCont.getChoiceArray(i); | |||
XmlCursor cCur = choice.newCursor(); | |||
XmlCursor innerCur = null; | |||
try { | |||
String requiresNS = cCur.namespaceForPrefix(choice.getRequires()); | |||
if (MAC_DML_NS.equalsIgnoreCase(requiresNS)) { | |||
// Mac DML usually contains PDFs ... | |||
continue; | |||
} | |||
innerCur = selectProperty(cCur, path, offset, reparseAlternate, true); | |||
if (innerCur != null) { | |||
return innerCur; | |||
} | |||
} finally { | |||
if (innerCur != cCur) { | |||
cCur.dispose(); | |||
} | |||
} | |||
} | |||
if (!alterCont.isSetFallback()) { | |||
return null; | |||
} | |||
XmlCursor fCur = alterCont.getFallback().newCursor(); | |||
XmlCursor innerCur = null; | |||
try { | |||
innerCur = selectProperty(fCur, path, offset, reparseAlternate, true); | |||
return innerCur; | |||
} finally { | |||
if (innerCur != fCur) { | |||
fCur.dispose(); | |||
} | |||
} | |||
} | |||
/** | |||
* Walk up the inheritance tree and fetch shape properties.<p> | |||
* |
@@ -17,7 +17,14 @@ | |||
package org.apache.poi.xslf; | |||
import static org.apache.poi.POITestCase.assertContains; | |||
import static org.junit.Assert.*; | |||
import static org.apache.poi.xslf.XSLFTestDataSamples.openSampleDocument; | |||
import static org.junit.Assert.assertArrayEquals; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import java.awt.Color; | |||
import java.awt.Dimension; | |||
@@ -66,6 +73,7 @@ import org.apache.poi.xslf.usermodel.XSLFAutoShape; | |||
import org.apache.poi.xslf.usermodel.XSLFGroupShape; | |||
import org.apache.poi.xslf.usermodel.XSLFHyperlink; | |||
import org.apache.poi.xslf.usermodel.XSLFNotes; | |||
import org.apache.poi.xslf.usermodel.XSLFObjectShape; | |||
import org.apache.poi.xslf.usermodel.XSLFPictureData; | |||
import org.apache.poi.xslf.usermodel.XSLFPictureShape; | |||
import org.apache.poi.xslf.usermodel.XSLFRelation; | |||
@@ -89,7 +97,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void bug62929() throws Exception { | |||
try(XMLSlideShow ss1 = XSLFTestDataSamples.openSampleDocument("missing-blip-fill.pptx")) { | |||
try(XMLSlideShow ss1 = openSampleDocument("missing-blip-fill.pptx")) { | |||
assertEquals(1, ss1.getSlides().size()); | |||
XSLFSlide slide = ss1.getSlides().get(0); | |||
@@ -108,7 +116,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void bug62736() throws Exception { | |||
XMLSlideShow ss1 = XSLFTestDataSamples.openSampleDocument("bug62736.pptx"); | |||
XMLSlideShow ss1 = openSampleDocument("bug62736.pptx"); | |||
assertEquals(1, ss1.getSlides().size()); | |||
@@ -332,7 +340,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void bug51187() throws Exception { | |||
XMLSlideShow ss1 = XSLFTestDataSamples.openSampleDocument("51187.pptx"); | |||
XMLSlideShow ss1 = openSampleDocument("51187.pptx"); | |||
assertEquals(1, ss1.getSlides().size()); | |||
@@ -373,7 +381,7 @@ public class TestXSLFBugs { | |||
*/ | |||
@Test | |||
public void tika705() throws Exception { | |||
XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("with_japanese.pptx"); | |||
XMLSlideShow ss = openSampleDocument("with_japanese.pptx"); | |||
// Should have one slide | |||
assertEquals(1, ss.getSlides().size()); | |||
@@ -423,7 +431,7 @@ public class TestXSLFBugs { | |||
*/ | |||
@Test | |||
public void bug54916() throws IOException { | |||
try (XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("OverlappingRelations.pptx")) { | |||
try (XMLSlideShow ss = openSampleDocument("OverlappingRelations.pptx")) { | |||
XSLFSlide slide; | |||
// Should find 4 slides | |||
@@ -452,7 +460,7 @@ public class TestXSLFBugs { | |||
*/ | |||
@Test | |||
public void bug56812() throws Exception { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("56812.pptx"); | |||
XMLSlideShow ppt = openSampleDocument("56812.pptx"); | |||
int internalPictures = 0; | |||
int externalPictures = 0; | |||
@@ -485,7 +493,7 @@ public class TestXSLFBugs { | |||
@Test | |||
@Ignore("Similar to TestFontRendering it doesn't make sense to compare images because of tiny rendering differences in windows/unix") | |||
public void bug54542() throws Exception { | |||
XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("54542_cropped_bitmap.pptx"); | |||
XMLSlideShow ss = openSampleDocument("54542_cropped_bitmap.pptx"); | |||
Dimension pgsize = ss.getPageSize(); | |||
@@ -676,7 +684,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void bug58205() throws IOException { | |||
XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("themes.pptx"); | |||
XMLSlideShow ss = openSampleDocument("themes.pptx"); | |||
int i = 1; | |||
for (XSLFSlideMaster sm : ss.getSlideMasters()) { | |||
@@ -688,14 +696,14 @@ public class TestXSLFBugs { | |||
@Test | |||
public void bug55791a() throws IOException { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("45541_Footer.pptx"); | |||
XMLSlideShow ppt = openSampleDocument("45541_Footer.pptx"); | |||
removeAndCreateSlide(ppt); | |||
ppt.close(); | |||
} | |||
@Test | |||
public void bug55791b() throws IOException { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("SampleShow.pptx"); | |||
XMLSlideShow ppt = openSampleDocument("SampleShow.pptx"); | |||
removeAndCreateSlide(ppt); | |||
ppt.close(); | |||
} | |||
@@ -708,7 +716,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void blibFillAlternateContent() throws IOException { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("2411-Performance_Up.pptx"); | |||
XMLSlideShow ppt = openSampleDocument("2411-Performance_Up.pptx"); | |||
XSLFPictureShape ps = (XSLFPictureShape)ppt.getSlides().get(4).getShapes().get(0); | |||
assertNotNull(ps.getPictureData()); | |||
ppt.close(); | |||
@@ -781,7 +789,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void bug55714() throws IOException { | |||
XMLSlideShow srcPptx = XSLFTestDataSamples.openSampleDocument("pptx2svg.pptx"); | |||
XMLSlideShow srcPptx = openSampleDocument("pptx2svg.pptx"); | |||
XMLSlideShow newPptx = new XMLSlideShow(); | |||
XSLFSlide srcSlide = srcPptx.getSlides().get(0); | |||
XSLFSlide newSlide = newPptx.createSlide(); | |||
@@ -807,7 +815,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void bug59273() throws IOException { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("bug59273.potx"); | |||
XMLSlideShow ppt = openSampleDocument("bug59273.potx"); | |||
ppt.getPackage().replaceContentType( | |||
XSLFRelation.PRESENTATIONML_TEMPLATE.getContentType(), | |||
XSLFRelation.MAIN.getContentType() | |||
@@ -851,7 +859,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void bug60715() throws IOException { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("bug60715.pptx"); | |||
XMLSlideShow ppt = openSampleDocument("bug60715.pptx"); | |||
ppt.createSlide(); | |||
ppt.close(); | |||
} | |||
@@ -887,7 +895,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void test60810() throws IOException { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("60810.pptx"); | |||
XMLSlideShow ppt = openSampleDocument("60810.pptx"); | |||
for(XSLFSlide slide : ppt.getSlides()) { | |||
XSLFNotes notesSlide = ppt.getNotesSlide(slide); | |||
assertNotNull(notesSlide); | |||
@@ -898,7 +906,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void test60042() throws IOException { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("60042.pptx"); | |||
XMLSlideShow ppt = openSampleDocument("60042.pptx"); | |||
ppt.removeSlide(0); | |||
ppt.createSlide(); | |||
ppt.close(); | |||
@@ -906,7 +914,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void test61515() throws IOException { | |||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("61515.pptx"); | |||
XMLSlideShow ppt = openSampleDocument("61515.pptx"); | |||
ppt.removeSlide(0); | |||
assertEquals(1, ppt.createSlide().getRelations().size()); | |||
try { | |||
@@ -923,7 +931,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void testAptia() throws IOException { | |||
try (XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("aptia.pptx"); | |||
try (XMLSlideShow ppt = openSampleDocument("aptia.pptx"); | |||
XMLSlideShow saved = XSLFTestDataSamples.writeOutAndReadBack(ppt)) { | |||
assertEquals(ppt.getSlides().size(), saved.getSlides().size()); | |||
} | |||
@@ -932,7 +940,7 @@ public class TestXSLFBugs { | |||
@Ignore | |||
@Test | |||
public void testDivinoRevelado() throws IOException { | |||
try (XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("Divino_Revelado.pptx"); | |||
try (XMLSlideShow ppt = openSampleDocument("Divino_Revelado.pptx"); | |||
XMLSlideShow saved = XSLFTestDataSamples.writeOutAndReadBack(ppt)){ | |||
assertEquals(ppt.getSlides().size(), saved.getSlides().size()); | |||
} | |||
@@ -968,7 +976,7 @@ public class TestXSLFBugs { | |||
@Test | |||
public void bug63200() throws Exception { | |||
try (XMLSlideShow ss1 = XSLFTestDataSamples.openSampleDocument("63200.pptx")) { | |||
try (XMLSlideShow ss1 = openSampleDocument("63200.pptx")) { | |||
assertEquals(1, ss1.getSlides().size()); | |||
XSLFSlide slide = ss1.getSlides().get(0); | |||
@@ -982,4 +990,25 @@ public class TestXSLFBugs { | |||
assertNull(arrow.getFillColor()); | |||
} | |||
} | |||
@Test | |||
public void alternateContent() throws Exception { | |||
try (XMLSlideShow ppt = openSampleDocument("alterman_security.pptx")) { | |||
XSLFSlideMaster slide = ppt.getSlideMasters().get(0); | |||
XSLFObjectShape os = (XSLFObjectShape)slide.getShapes().get(0); | |||
// ctOleObject is nested in AlternateContent in this file | |||
// if there are casting errors, we would fail early and wouldn't reach this point anyway | |||
assertNotNull(os.getCTOleObject()); | |||
// accessing the picture data of the AlternateContent fallback part | |||
XSLFPictureData picData = os.getPictureData(); | |||
assertNotNull(picData); | |||
} | |||
try (XMLSlideShow ppt = openSampleDocument("2411-Performance_Up.pptx")) { | |||
XSLFSlide slide = ppt.getSlides().get(4); | |||
XSLFPictureShape ps = (XSLFPictureShape)slide.getShapes().get(0); | |||
assertEquals("image4.png", ps.getPictureData().getFileName()); | |||
assertEquals("Picture 5", ps.getShapeName()); | |||
} | |||
} | |||
} |