Java 尝试访问XSSFShape的父级会导致NullPointerException
在尝试时,我想通过检查Java 尝试访问XSSFShape的父级会导致NullPointerException,java,apache-poi,Java,Apache Poi,在尝试时,我想通过检查XSSFPictures的父项来区分XSSFShapeGroup的子项和非子项: 私有void traverseShapeContainer(ShapeContainer容器){ for(XSSFShape:container){ //这里没有提到其他类型的XSSFShape。 if(XSSFPicture的形状实例){ XSSFPicture图片=(XSSFPicture)形状; System.out.println(shape.getParent()instanceof
XSSFPictures
的父项来区分XSSFShapeGroup
的子项和非子项:
私有void traverseShapeContainer(ShapeContainer容器){
for(XSSFShape:container){
//这里没有提到其他类型的XSSFShape。
if(XSSFPicture的形状实例){
XSSFPicture图片=(XSSFPicture)形状;
System.out.println(shape.getParent()instanceof XSSFShapeGroup);//始终输出false
System.out.println(Objects.isNull(shape.getParent());//始终输出true
}else if(XSSFShapeGroup的形状实例){
XSSFShapeGroup shapeGroup=(XSSFShapeGroup)形状;
//访问XSSFShapeGroup的内部内容
traverseShapeContainer(形状组);
}
}
}
无论XSSFPicture
是否为XSSFShapeGroup
的子级,这对于每种情况都是相同的
在我执行了这两个测试来检查它的父项之后,这看起来特别奇怪
- 测试1:检查ShapeContainer是否是XSSFShapeGroup的实例
System.out.println(Objects.isNull(XSSFShapeGroup的容器实例));//输出:false
- 测试2:在访问子节点后查找父标记
if(XSSFPicture的形状实例){
XSSFPicture图片=(XSSFPicture)形状;
//“xdr:grpSp”是XSSFShapeGroup的标记
System.out.println(picture.getCTPicture().getDomNode().getParentNode().getNodeName()
.equals(“xdr:grpSp”);//输出:true
}
这清楚地表明父级确实存在,并且允许我们在过程中检查父级
我还没有检查其他类型的xssfshape
,例如XSSFSimpleShape
或XSSFConnector
。然而,由于它们都继承了相同的类,即,XSSFShape
,我想结果不会有太大的不同
因此,
XSSFShape.getParent()
可能有什么问题,或者我对这个问题的看法不正确吗?这是因为到目前为止(apache-poi
的不完整性(2021年5月,版本apache-poi 5.0.0
)。它影响形状组中的所有形状
XSSFShape.getParent
只返回XSSFShape
的类成员XSSFShapeGroup parent
。但是,在解析Office Open XML
绘图时,apache poi只执行以下操作:
...
} else if (obj instanceof CTGroupShape) {
shape = new XSSFShapeGroup(this, (CTGroupShape) obj);
}...
看
而XSSFShapeGroup
的构造函数就是这样做的
protected XSSFShapeGroup(XSSFDrawing drawing, CTGroupShape ctGroup) {
this.drawing = drawing;
this.ctGroup = ctGroup;
}
看
因此,这缺少遍历该组中的所有形状并将其父对象设置为该形状组。因此parent
总是null
因此,要么使用低级类获取父类,正如您在问题中已经显示的那样。或者,更好的做法是,在方法traverseShapeContainer(ShapeContainer container)
中检查容器,该容器是所有已遍历形状的父容器。您可以获取这是XSSFShapeGroup
还是XSSFDrawing
像这样:
...
... void traverseShapeContainer(ShapeContainer<XSSFShape> container) {
for (XSSFShape shape : container) {
// possible: XSSFConnector, XSSFGraphicFrame, XSSFPicture, XSSFShapeGroup, XSSFSimpleShape
if (shape instanceof XSSFConnector) {
XSSFConnector connector = (XSSFConnector)shape;
System.out.println(connector);
} else if (shape instanceof XSSFGraphicFrame) {
XSSFGraphicFrame graphicFrame = (XSSFGraphicFrame)shape;
System.out.println(graphicFrame);
} else if (shape instanceof XSSFPicture) {
XSSFPicture picture = (XSSFPicture)shape;
System.out.println(picture);
if (container instanceof XSSFDrawing) {
System.out.println("Picture is in drawing directly.");
} else if (container instanceof XSSFShapeGroup) {
System.out.println("Picture is in shape group.");
XSSFShapeGroup parent = (XSSFShapeGroup) container;
System.out.println("Parent is " + parent);
}
} else if (shape instanceof XSSFShapeGroup) { //we have a shape group
XSSFShapeGroup shapeGroup = (XSSFShapeGroup)shape;
System.out.println(shapeGroup);
traverseShapeContainer(shapeGroup); // we now can sinply get the XSSFShapeGroup as ShapeContainer<XSSFShape>
} else if (shape instanceof XSSFSimpleShape) {
XSSFSimpleShape simpleShape = (XSSFSimpleShape)shape;
System.out.println(simpleShape);
}
}
}
...
。。。
... void traverseShapeContainer(ShapeContainer容器){
对于(XSSFShape:container){
//可能:XSSFConnector、XSSFGraphicFrame、XSSFPicture、XSSFShapeGroup、XSSFSimpleShape
if(XSSFConnector的形状实例){
XSSFConnector连接器=(XSSFConnector)形状;
系统输出打印LN(连接器);
}else if(XSSFGraphicFrame的形状实例){
XSSFGraphicFrame graphicFrame=(XSSFGraphicFrame)形状;
System.out.println(图形框架);
}else if(XSSFPicture的形状实例){
XSSFPicture图片=(XSSFPicture)形状;
系统输出打印项次(图片);
if(XSSFDrawing的容器实例){
System.out.println(“图片直接在绘图中”);
}else if(XSSFShapeGroup的容器实例){
System.out.println(“图片在形状组中”);
XSSFShapeGroup父级=(XSSFShapeGroup)容器;
System.out.println(“父项为”+父项);
}
}else如果(XSSFShapeGroup的shape instanceof){//我们有一个shape组
XSSFShapeGroup shapeGroup=(XSSFShapeGroup)形状;
System.out.println(shapeGroup);
traverseShapeContainer(shapeGroup);//我们现在可以将XSSFShapeGroup用作ShapeContainer
}else if(XSSFSimpleShape的形状实例){
XSSFSimpleShape simpleShape=(XSSFSimpleShape)形状;
System.out.println(simpleShape);
}
}
}
...
也可以通知维护人员。@dodobird:这样做;-)。由于多种原因,我不会这样做。但是ApachePOI开发者社区的一些成员也阅读并参与了本文。