我正在尝试使用 Apache POI 提取有关 Word 文档中文本框的位置和尺寸的信息。在 Aspose.Words 中,有一些方法和类可以处理文本框和其他形状,这些在 Apache POI 中可用。如果有一种方法可以使用 Apache POI 提取有关文本框的位置和尺寸的信息,那将会很有帮助。
XWPFDocument document = new XWPFDocument(OPCPackage.open(fis));
List<XWPFParagraph> paragraphs = document.getParagraphs();
XmlObject[] textBoxObjects;
for(XWPFParagraph paragraph : paragraphs)
{
textBoxObjects = paragraph.getCTP().selectPath(
"declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' " +
"declare namespace wps='http://schemas.microsoft.com/office/word/2010/wordprocessingShape' " +
"declare namespace v='urn:schemas-microsoft-com:vml'"+ ".//*/wps:txbx/w:txbxContent | .//*/v:textbox/w:txbxContent");
//
for (int i =0; i < textBoxObjects.length; i++){
XWPFParagraph embeddedPara = null;
try {
XmlObject[] paraObjects = textBoxObjects[i].selectChildren(new QName("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "p"));
for (int j=0; j<paraObjects.length; j++) {
embeddedPara = new XWPFParagraph(CTP.Factory.parse(paraObjects[j].xmlText()), paragraph.getBody());
System.out.println(embeddedPara.getText());
}
}
}
使用上面的脚本,我从文本框中提取文本,但我还需要有关文本框的位置和尺寸的信息才能继续。
如果有一种方法可以提取这些信息,那将会很有帮助。
包含文本框的 Word 文档的屏幕截图示例
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 wp14 w15"><w:body><w:p><w:pPr><w:pStyle w:val="Normal"/><w:bidi w:val="0"/><w:jc w:val="left"/><w:rPr></w:rPr></w:pPr><w:r><w:rPr></w:rPr><mc:AlternateContent><mc:Choice Requires="wps"><w:drawing><wp:anchor behindDoc="0" distT="0" distB="0" distL="0" distR="0" simplePos="0" locked="0" layoutInCell="1" allowOverlap="1" relativeHeight="2"><wp:simplePos x="0" y="0"/><wp:positionH relativeFrom="column"><wp:posOffset>457200</wp:posOffset></wp:positionH><wp:positionV relativeFrom="paragraph"><wp:posOffset>565150</wp:posOffset></wp:positionV><wp:extent cx="1664970" cy="1148715"/><wp:effectExtent l="0" t="0" r="0" b="0"/><wp:wrapNone/><wp:docPr id="1" name="Text Frame 1"></wp:docPr><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"><wps:wsp><wps:cNvSpPr/><wps:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="1665000" cy="1148760"/></a:xfrm><a:prstGeom prst="rect"><a:avLst></a:avLst></a:prstGeom><a:noFill/><a:ln w="0"><a:noFill/></a:ln></wps:spPr><wps:style><a:lnRef idx="0"></a:lnRef><a:fillRef idx="0"/><a:effectRef idx="0"></a:effectRef><a:fontRef idx="minor"/></wps:style><wps:txbx><w:txbxContent><w:p><w:pPr><w:pStyle w:val="FrameContents"/><w:overflowPunct w:val="false"/><w:bidi w:val="0"/><w:rPr><w:color w:val="000000"/></w:rPr></w:pPr><w:r><w:rPr><w:color w:val="000000"/></w:rPr><w:t>Text 1</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="FrameContents"/><w:overflowPunct w:val="false"/><w:bidi w:val="0"/><w:rPr><w:color w:val="000000"/></w:rPr></w:pPr><w:r><w:rPr><w:color w:val="000000"/></w:rPr></w:r></w:p></w:txbxContent></wps:txbx><wps:bodyPr lIns="0" rIns="0" tIns="0" bIns="0" anchor="t"><a:noAutofit/></wps:bodyPr></wps:wsp></a:graphicData></a:graphic></wp:anchor></w:drawing></mc:Choice>
在上面的 XML 文件中,有锚标记的 posOffset 值,我希望能够检索该值以查找 Word 文档中任何绘图对象的位置。
Apache POI
XWPF
不支持 XWPFDocument
中的任何形状及其主体元素。对于文本框形状也是如此。
但是,当然,信息都在背后的 XML 中
XWPFDocument
。 因此,如果知道哪些 XML 元素具有特殊含义,那么就可以使用 XML 方法从该 XML 中获取所有信息。
在如何从 apache POI XWPFDocument 获取绘图?我已经展示了如何从 Apache POI
XWPFDocument
获取所有绘图。但下一个问题是如何从绘图元素中获取内容。获得 CTTxbxContent
的方法在链接的答案中。但要获得形状尺寸,需要其他方法。
微软决定使用许多不同的奇怪的长度测量单位并没有让事情变得更容易。有时使用缇(二十分之一英寸),有时使用 EMU(英制公制单位),有时使用半点、八分之一等等……始终不使用真正的公制单位,例如米的部分(厘米、毫米、.. )被使用。欢迎来到 21 世纪。
以下代码显示了从 XML 保存的形状范围中获取宽度和高度的方法,无论是从内联形状还是从锚定形状。
import java.io.FileInputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
import java.util.List;
import java.util.ArrayList;
public class WordGetAllDrawingsFromRuns {
private static List<CTDrawing> getAllDrawings(XWPFRun run) throws Exception {
CTR ctR = run.getCTR();
XmlCursor cursor = ctR.newCursor();
cursor.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:drawing");
List<CTDrawing> drawings = new ArrayList<CTDrawing>();
while (cursor.hasNextSelection()) {
cursor.toNextSelection();
XmlObject obj = cursor.getObject();
CTDrawing drawing = CTDrawing.Factory.parse(obj.newInputStream());
drawings.add(drawing);
}
return drawings;
}
private static String getTextBoxContent(CTDrawing drawing) {
StringBuilder result = new StringBuilder();
XmlCursor cursor = drawing.newCursor();
cursor.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:txbxContent");
while (cursor.hasNextSelection()) {
cursor.toNextSelection();
result.append(cursor.getTextValue());
}
return result.toString();
}
private static Integer getAnchorExtentWidthInEMU(CTDrawing drawing) {
Integer result = null;
XmlCursor cursor = drawing.newCursor();
cursor.selectPath("declare namespace wp='http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing' .//wp:anchor/wp:extent");
while (cursor.hasNextSelection()) {
cursor.toNextSelection();
String cx = cursor.getAttributeText(new javax.xml.namespace.QName("cx"));
result = Integer.valueOf(cx);
}
return result;
}
private static Integer getInlineExtentWidthInEMU(CTDrawing drawing) {
Integer result = null;
XmlCursor cursor = drawing.newCursor();
cursor.selectPath("declare namespace wp='http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing' .//wp:inline/wp:extent");
while (cursor.hasNextSelection()) {
cursor.toNextSelection();
String cx = cursor.getAttributeText(new javax.xml.namespace.QName("cx"));
result = Integer.valueOf(cx);
}
return result;
}
private static Integer getAnchorExtentHeightInEMU(CTDrawing drawing) {
Integer result = null;
XmlCursor cursor = drawing.newCursor();
cursor.selectPath("declare namespace wp='http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing' .//wp:anchor/wp:extent");
while (cursor.hasNextSelection()) {
cursor.toNextSelection();
String cy = cursor.getAttributeText(new javax.xml.namespace.QName("cy"));
result = Integer.valueOf(cy);
}
return result;
}
private static Integer getInlineExtentHeightInEMU(CTDrawing drawing) {
Integer result = null;
XmlCursor cursor = drawing.newCursor();
cursor.selectPath("declare namespace wp='http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing' .//wp:inline/wp:extent");
while (cursor.hasNextSelection()) {
cursor.toNextSelection();
String cy = cursor.getAttributeText(new javax.xml.namespace.QName("cy"));
result = Integer.valueOf(cy);
}
return result;
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument(new FileInputStream("WordContainingTextBoxes.docx"));
for (IBodyElement bodyElement : document.getBodyElements()) {
if (bodyElement instanceof XWPFParagraph) {
XWPFParagraph paragraph = (XWPFParagraph) bodyElement;
for(IRunElement runElement : paragraph.getIRuns()) {
if (runElement instanceof XWPFRun) {
XWPFRun run = (XWPFRun) runElement;
List<CTDrawing> drawings = getAllDrawings(run);
for (CTDrawing drawing : drawings) {
String textBoxContent = getTextBoxContent(drawing);
System.out.println("text box content: " + textBoxContent);
Integer width = getAnchorExtentWidthInEMU(drawing);
if (width == null) width = getInlineExtentWidthInEMU(drawing);
System.out.println("anchor or inline width: " + (double)width/Units.EMU_PER_INCH + " inch");
Integer height = getAnchorExtentHeightInEMU(drawing);
if (height == null) height = getInlineExtentHeightInEMU(drawing);
System.out.println("anchor or inline height: " + (double)height/Units.EMU_PER_INCH + " inch");
}
}
}
}
}
document.close();
}
}
获取形状的位置会更加昂贵。第一个问题是,位置与什么相关?内联形状充当文本流中的字符。因此位置取决于内联形状之前的文本,包括字体大小、字符间距、行间距、自动换行等。而且锚定形状也可以锚定到不同的文本和页面元素。它们可以锚定到段落、页面边框、叶边框……我无法在此处显示所有这些的代码。如果您为 Aspose Words 付费,您知道您所付出的代价了吗?