尝试访问 XSSFShape 的父级会导致 NullPointerException
Trying to access the parent of an XSSFShape results in NullPointerException
在尝试 时,我想区分 XSSFPictures
哪些是 XSSFShapeGroup
的子代,哪些不是 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
是否是 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
。但是,由于它们都继承了相同的 class,即 XSSFShape
,我想结果不会有太大差异。
那么 XSSFShape.getParent()
可能有什么问题或者我对问题的看法不正确?
这是因为 apache poi
直到现在(2021 年 5 月,版本 apache poi 5.0.0
)还不完整。它会影响形状组中的所有形状。
XSSFShape.getParent
只是 returns XSSFShape
的 class 成员 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 设置为该形状组。所以 parent
永远是 null
.
所以要么你得到 parent 使用低级别 classes,正如你已经在你的问题中显示的那样。或者,更好的是,您在方法 traverseShapeContainer(ShapeContainer<XSSFShape> container)
中检查 container
,其中 是 所有遍历形状的 parent 容器。你可以得到这是 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);
}
}
}
...
在尝试 XSSFPictures
哪些是 XSSFShapeGroup
的子代,哪些不是 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
是否是 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
。但是,由于它们都继承了相同的 class,即 XSSFShape
,我想结果不会有太大差异。
那么 XSSFShape.getParent()
可能有什么问题或者我对问题的看法不正确?
这是因为 apache poi
直到现在(2021 年 5 月,版本 apache poi 5.0.0
)还不完整。它会影响形状组中的所有形状。
XSSFShape.getParent
只是 returns XSSFShape
的 class 成员 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 设置为该形状组。所以 parent
永远是 null
.
所以要么你得到 parent 使用低级别 classes,正如你已经在你的问题中显示的那样。或者,更好的是,您在方法 traverseShapeContainer(ShapeContainer<XSSFShape> container)
中检查 container
,其中 是 所有遍历形状的 parent 容器。你可以得到这是 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);
}
}
}
...