java - 尝试访问 XSSFShape 的父级导致 NullPointerException
问题描述
在尝试遍历 ShapeContainer 的内部内容时,我想通过检查它的父级来区分XSSFPictures
哪些是子级XSSFShapeGroup
,哪些不是:
private void traverseShapeContainer(ShapeContainer<XSSFShape> container) {
for (XSSFShape shape : container) {
// Other types of XSSFShapes have not been mentioned here.
if (shape instanceof XSSFPicture) {
XSSFPicture picture = (XSSFPicture) shape;
System.out.println(shape.getParent() instanceof XSSFShapeGroup); // Always outputs false
System.out.println(Objects.isNull(shape.getParent())); // Always outputs true
} else if (shape instanceof XSSFShapeGroup) {
XSSFShapeGroup shapeGroup = (XSSFShapeGroup) shape;
// accessing inner contents of XSSFShapeGroup
traverseShapeContainer(shapeGroup);
}
}
}
XSSFPicture
无论an是否是a的孩子,这对于每种情况都是相同的XSSFShapeGroup
。
在我执行这两个测试以检查它的父母之后,这似乎特别奇怪。
- 测试 1:检查 ShapeContainer 是否是 XSSFShapeGroup 的实例。
System.out.println(Objects.isNull(container instanceof XSSFShapeGroup)); // Output: false
- 测试2:访问子节点后寻找父标签。
if (shape instanceof XSSFPicture) {
XSSFPicture picture = (XSSFPicture) shape;
// "xdr:grpSp" is the tag for XSSFShapeGroup
System.out.println(picture.getCTPicture().getDomNode().getParentNode().getNodeName()
.equals("xdr:grpSp")); // Output: true
}
这清楚地表明父级确实存在,并且还允许我们在此过程中检查父级。
我还没有检查过其他类型的,XSSFShapes
比如XSSFSimpleShape
或者XSSFConnector
还没有。但是,由于它们都继承同一个类,即,XSSFShape
我想结果不会有太大不同。
那么可能有什么问题,XSSFShape.getParent()
或者我对问题的看法不正确?
解决方案
这是因为apache poi
到目前为止(2021 年 5 月,版本apache poi 5.0.0
)的不完整。它会影响形状组中的所有形状。
XSSFShape.getParent
简单地返回XSSFShapeGroup parent
. XSSFShape
但是在解析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
。
因此,正如您在问题中已经显示的那样,您可以使用低级类来获取父级。或者,更好的是,你检查container
你的方法traverseShapeContainer(ShapeContainer<XSSFShape> container)
,它是所有遍历形状的父容器。您可以知道这是 aXSSFShapeGroup
还是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);
}
}
}
...
推荐阅读
- vue.js - Vue路由器 - 克服下一个({})未捕获(承诺)未定义错误
- spring - 在 Spring 中动态解析静态内容
- python - logger.setLevel 没有效果
- c - 优先队列和堆(这对我来说很难......)
- bash - 将 stat 命令输出与 bash 中的字符串进行比较
- azure-devops - 如何使用 REST API 更新任务组
- xamarin - 使用 SKCanvasView 渲染图块网格
- django - django.core.exceptions.AppRegistryNotReady:加载 wsgi.py 时尚未加载应用程序
- docker - docker:已安装卷的权限错误
- c# - 在漫游时随机移动 Picturebox