如何用Apache POI 5.2.2清除内容控件全部内容(含内部控件)
彻底清除Apache POI 5.2.2中外部内容控件的全部内容(含内部嵌套控件)
问题场景
使用Apache POI 5.2.2处理Word文档时,遇到包含嵌套内容控件的结构,现有代码仅能清除部分内容,内部嵌套的内容控件无法被清除,需要修改代码实现彻底清空外部内容控件内的所有内容。
嵌套内容控件的XML结构
xml-fragment ....xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"> <w:sdtPr> <w:rPr> <w:sz w:val="24"/> <w:szCs w:val="24"/> </w:rPr> <w:alias w:val="condition:Include Clause B-equals-SOMETHINGELSE"/> <w:tag w:val="condition:Include Clause B-equals-SOMETHINGELSE"/> <w:id w:val="-352886319"/> <w:placeholder> <w:docPart w:val="40B8349151E69B4080AC951B34BB7066"/> </w:placeholder> <w15:color w:val="0000FF"/> <w15:appearance w15:val="tags"/> </w:sdtPr> <w:sdtContent> <w:sdt> <w:sdtPr> <w:rPr> <w:sz w:val="24"/> <w:szCs w:val="24"/> </w:rPr> <w:alias w:val="clause:Clause B"/> <w:tag w:val="clause:Clause B"/> <w:id w:val="2110933031"/> <w:placeholder> <w:docPart w:val="DE22C8B6F70C8945AFCC799440DC836B"/> </w:placeholder> <w:showingPlcHdr/> <w15:color w:val="0000FF"/> <w15:appearance w15:val="tags"/> </w:sdtPr> <w:sdtContent> <w:sdt> <w:sdtContent> <w:r w:rsidRPr="002619CB"> <w:rPr> <w:color w:val="FF0000"/> </w:rPr> <w:t xml:space="preserve">This is Clause </w:t> </w:r> <w:r w:rsidRPr="002619CB"> <w:rPr> <w:color w:val="FF0000"/> </w:rPr> <w:t>B</w:t> </w:r> ....... <w:r> <w:t/> <w:cr/> </w:r> </w:sdtContent> </w:sdt> </w:sdtContent> </w:sdt> </w:sdtContent> </xml-fragment>
现有问题代码
void setContentBlank() { if (this.object instanceof CTSdtBlock) { CTSdtBlock ctSdtBlock = (CTSdtBlock)this.object if (ctSdtBlock.isSetSdtContent()) { CTSdtContentBlock sdtContentBlock = ctSdtBlock.getSdtContent() sdtContentBlock.PList.clear() } } else if (this.object instanceof CTSdtRun) { CTSdtRun ctSdtRun = (CTSdtRun)this.object if (ctSdtRun.isSetSdtContent()) { CTSdtContentRun sdtContentRun = ctSdtRun.getSdtContent() CTR[] ctRArray = [] sdtContentRun.setRArray(ctRArray) } } else if (this.object instanceof CTSdtCell) { CTSdtCell ctSdtCell = (CTSdtCell)this.object if (ctSdtCell.isSetSdtContent()) { CTSdtContentCell sdtContentCell = ctSdtCell.getSdtContent() for (int c = 0; c < sdtContentCell.getTcList().size(); c++) { CTTc ctTc = sdtContentCell.getTcList().get(c) ctTc.PList.clear() } } } }
问题原因
现有代码仅清空了内容控件中部分类型的子元素(如段落PList、文本段RArray),但嵌套的内容控件是以<w:sdt>元素的形式存在于内容控件的sdtContent中,不属于这些被清空的列表,因此会被保留下来。
解决方案
直接操作内容控件的DOM节点,移除所有子元素,实现彻底清空。修改后的代码如下:
void setContentBlank() { if (this.object instanceof CTSdtBlock) { CTSdtBlock ctSdtBlock = (CTSdtBlock) this.object; if (ctSdtBlock.isSetSdtContent()) { CTSdtContentBlock sdtContentBlock = ctSdtBlock.getSdtContent(); // 移除sdtContent下的所有子节点,包括嵌套的内容控件 sdtContentBlock.getDomNode().removeAllChildren(); } } else if (this.object instanceof CTSdtRun) { CTSdtRun ctSdtRun = (CTSdtRun) this.object; if (ctSdtRun.isSetSdtContent()) { CTSdtContentRun sdtContentRun = ctSdtRun.getSdtContent(); // 移除所有子节点,包括嵌套的sdt sdtContentRun.getDomNode().removeAllChildren(); } } else if (this.object instanceof CTSdtCell) { CTSdtCell ctSdtCell = (CTSdtCell) this.object; if (ctSdtCell.isSetSdtContent()) { CTSdtContentCell sdtContentCell = ctSdtCell.getSdtContent(); // 移除sdtContent下的所有子节点 sdtContentCell.getDomNode().removeAllChildren(); } } }
代码说明
- 调用
getDomNode()获取内容控件内容的底层DOM节点,通过removeAllChildren()一次性移除所有子元素,包括嵌套的内容控件、段落、文本等所有内容。 - 这种方式比单独清空各个元素列表更彻底,避免遗漏嵌套的内容控件或其他类型的子元素。
内容的提问来源于stack exchange,提问作者bytor99999
相关产品推荐
相关产品推荐

