发现通过遍历所有的XWPFParagraph不能拿到文档自动生成的目录(如下图这种“带框的”)
原因是:在xml里面,自动生成的目录不在<w:p>中,而在<w:sdt>中 的<w:sdtContent>中的<w:p>中
然而从XWPFDocument中并不能直接获取XWPFSDT,所以要先获得XWPFSDT、XWPFParagraph、XWPFTable类实现的接口IBodyElement,这样就可以获取目录的内容了。
代码如下:
XWPFDocument doc = new XWPFDocument(is);
Iterator<IBodyElement> bodyElementsIterator = doc.getBodyElementsIterator();
while (bodyElementsIterator.hasNext()) {
IBodyElement bodyElement = bodyElementsIterator.next();
// 根据元素是不是需要的XWPFSDT
if (bodyElement instanceof XWPFSDT) {
//getContent获取内容
System.out.println(((XWPFSDT) bodyElement).getContent());
}
}
但是这样还是不能获取到目录中字体的样式,因为XWPFSDT类中压根没写这玩意,所以想获取样式该怎么办呢?
观察XWPFSDT类,发现构造函数之中有样式,如下图
于是选择重写一个和它类似的类,代码如下...(第一次这么干,有没有懂的大手子指点一下这样做有没有啥危险、正常应该怎么办啊..)
public class MyXWPFSDT extends XWPFAbstractSDT implements IBodyElement, IRunBody, ISDTContents, IRunElement {
private final ISDTContent content;
private CTSdtBlock block;
public MyXWPFSDT(CTSdtRun sdtRun, IBody part) {
super(sdtRun.getSdtPr(), part);
this.content = new XWPFSDTContent(sdtRun.getSdtContent(), part, this);
}
public MyXWPFSDT(CTSdtBlock block, IBody part) {
super(block.getSdtPr(), part);
this.content = new XWPFSDTContent(block.getSdtContent(), part, this);
this.block = block;
}
public ISDTContent getContent() {
return this.content;
}
public CTSdtBlock getBlock(){
return this.block;
}
}
然后修改一下XWPFDocument中的onDocumentRead()方法。
当遍历到CTSdtBlock时,把我们新写的MyXWPFSDT加入bodyElements列表中,代码如下(本来是想写类继承XWPFDocument的,但是XWPFDocument很多调用XWPFDocument为返回值的函数,感觉很麻烦..所以直接修改了...):
protected void onDocumentRead() throws IOException {
try {
InputStream stream = this.getPackagePart().getInputStream();
Throwable var3 = null;
DocumentDocument doc;
try {
doc = (DocumentDocument)DocumentDocument.Factory.parse(stream, POIXMLTypeLoader.DEFAULT_XML_OPTIONS);
this.ctDocument = doc.getDocument();
} catch (Throwable var15) {
var3 = var15;
throw var15;
} finally {
if (stream != null) {
if (var3 != null) {
try {
stream.close();
} catch (Throwable var14) {
var3.addSuppressed(var14);
}
} else {
stream.close();
}
}
}
this.initFootnotes();
XmlCursor docCursor = this.ctDocument.newCursor();
docCursor.selectPath("./*");
while(true) {
XmlObject o;
do {
if (!docCursor.toNextSelection()) {
docCursor.dispose();
if (doc.getDocument().getBody().getSectPr() != null) {
this.headerFooterPolicy = new XWPFHeaderFooterPolicy(this);
}
Iterator var20 = this.getRelationParts().iterator();
while(true) {
while(var20.hasNext()) {
POIXMLDocumentPart.RelationPart rp = (POIXMLDocumentPart.RelationPart)var20.next();
POIXMLDocumentPart p = rp.getDocumentPart();
String relation = rp.getRelationship().getRelationshipType();
if (relation.equals(XWPFRelation.STYLES.getRelation())) {
this.styles = (XWPFStyles)p;
this.styles.onDocumentRead();
} else if (relation.equals(XWPFRelation.NUMBERING.getRelation())) {
this.numbering = (XWPFNumbering)p;
this.numbering.onDocumentRead();
} else if (relation.equals(XWPFRelation.FOOTER.getRelation())) {
XWPFFooter footer = (XWPFFooter)p;
this.footers.add(footer);
footer.onDocumentRead();
} else if (relation.equals(XWPFRelation.HEADER.getRelation())) {
XWPFHeader header = (XWPFHeader)p;
this.headers.add(header);
header.onDocumentRead();
} else if (relation.equals(XWPFRelation.COMMENT.getRelation())) {
this.comments = (XWPFComments)p;
this.comments.onDocumentRead();
} else if (relation.equals(XWPFRelation.SETTINGS.getRelation())) {
this.settings = (XWPFSettings)p;
this.settings.onDocumentRead();
} else if (relation.equals(XWPFRelation.IMAGES.getRelation())) {
XWPFPictureData picData = (XWPFPictureData)p;
picData.onDocumentRead();
this.registerPackagePictureData(picData);
this.pictures.add(picData);
} else if (relation.equals(XWPFRelation.CHART.getRelation())) {
XWPFChart chartData = (XWPFChart)p;
this.charts.add(chartData);
} else if (relation.equals(XWPFRelation.GLOSSARY_DOCUMENT.getRelation())) {
Iterator var7 = p.getRelations().iterator();
while(var7.hasNext()) {
POIXMLDocumentPart gp = (POIXMLDocumentPart)var7.next();
POIXMLDocumentPart._invokeOnDocumentRead(gp);
}
}
}
this.initHyperlinks();
return;
}
}
o = docCursor.getObject();
} while(!(o instanceof CTBody));
XmlCursor bodyCursor = o.newCursor();
bodyCursor.selectPath("./*");
while(bodyCursor.toNextSelection()) {
XmlObject bodyObj = bodyCursor.getObject();
if (bodyObj instanceof CTP) {
XWPFParagraph p = new XWPFParagraph((CTP)bodyObj, this);
this.bodyElements.add(p);
this.paragraphs.add(p);
} else if (bodyObj instanceof CTTbl) {
XWPFTable t = new XWPFTable((CTTbl)bodyObj, this);
this.bodyElements.add(t);
this.tables.add(t);
} else if (bodyObj instanceof CTSdtBlock) {
XWPFSDT c = new XWPFSDT((CTSdtBlock)bodyObj, this);
MyXWPFSDT cc = new MyXWPFSDT((CTSdtBlock)bodyObj, this);
this.bodyElements.add(c);
this.contentControls.add(c);
this.bodyElements.add(cc);
this.mycontentControls.add(cc);
}
}
bodyCursor.dispose();
}
} catch (XmlException var17) {
throw new POIXMLException(var17);
}
}
最后就是获取目录内容、样式的代码了,代码如下
@Test
void Testdirectory() throws Exception {
InputStream is = new FileInputStream("...");
XWPFDocument doc = new XWPFDocument(is);
Iterator<IBodyElement> bodyElementsIterator = doc.getBodyElementsIterator();
while (bodyElementsIterator.hasNext()) {
IBodyElement bodyElement = bodyElementsIterator.next();
if (bodyElement instanceof MyXWPFSDT) {
System.out.println(((MyXWPFSDT) bodyElement).getContent().getText());
CTSdtBlock block = ((MyXWPFSDT) bodyElement).getBlock();
System.out.println("***********");
CTSdtContentBlock sdtContent = block.getSdtContent();
CTP[] pArray = sdtContent.getPArray();
System.out.println(pArray.length);
for (int i = 0; i< pArray.length; i++){
System.out.println("-----------");
//这就是样式
System.out.println(pArray[i].getPPr());
}
System.out.println("***********");
}
}