2

我正在使用 docx4j 来读取和解析 .docx 文件,但是当我遍历段落时,它不是一次性读取所有段落。下面是我正在使用的代码示例。

private void replaceAcrAndDef(String acrName, String acrParensName, String oldDef, String newDef){
    String XPATH_TO_SELECT_TEXT_NODES = "//w:t";
    List<Object> paragraphs = template.getMainDocumentPart().getJAXBNodesViaXPath(XPATH_TO_SELECT_TEXT_NODES, true);
    for (Object obj : paragraphs){
        Text text = (Text) ((JAXBElement)obj).getValue();
        String textValue = text.getValue();
        System.out.println(textValue);
 }

在上面的 for 循环的一次通过中,这将读作第一段 -

“团队通过对任务、测试、行政和一般服务网络和系统有直接的 MDA 经验,对要求有深刻的理解。重新建立一个对任务、流程和优先事项有深入了解的低风险、反应迅速的团队的好处。我们的综合利用"

但它缺少该段落的最后部分。这将在连续传球中出现。我在这里做错了什么。

该段的全部内容是:

团队通过对任务、测试、行政和一般服务网络和系统有直接的 MDA 经验,对要求有深刻的理解。这样做的好处是风险低、反应迅速的团队,对使命、流程和优先事项有明确的了解。我们使用基于集成信息技术的基于角色的管理 (RBA) 方法与相关承包商、现有流程和我们的补充流程协同工作。

我不知道是否有办法获取整个段落,但如果有的话会很好,因为我需要逐段进行字符串替换。

4

3 回答 3

5

我将我的评论扩展到一个答案:

我猜,该段落包含多个文本元素(w:t)。您能否提供有关此问题的示例文档?在段落元素上使用 TextUtils.extractText 提取文本怎么样?

尝试 P.toString()。那里引用了 TextUtils,您也可以尝试使用 StringWriter。


使用P.toString()

// Request paragraphs
final String XPATH_TO_SELECT_TEXT_NODES = "//w:p";
final List<Object> jaxbNodes = wordMLPackage.getMainDocumentPart().getJAXBNodesViaXPath(XPATH_TO_SELECT_TEXT_NODES, true);

for (Object jaxbNode : jaxbNodes){
    final String paragraphString = jaxbNode.toString();
    System.out.println(paragraphString);
}

使用TextUtils.extractText(...)StringWriter

for (Object jaxbNode : jaxbNodes){
    final StringWriter stringWriter = new StringWriter();
    TextUtils.extractText(jaxbNode, stringWriter);
    final String paragraphString = stringWriter.toString();
    System.out.println(paragraphString);
}
于 2012-11-05T21:50:05.323 回答
2

我正在使用这些方法使用 docx4j 执行搜索和替换(灵感来自http://www.smartjava.org/content/create-complex-word-docx-documents-programatically-docx4j):

public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
    List<Object> result = new ArrayList<Object>();
    if (obj instanceof JAXBElement) obj = ((JAXBElement<?>) obj).getValue();

    if (obj.getClass().equals(toSearch))
        result.add(obj);
    else if (obj instanceof ContentAccessor) {
        List<?> children = ((ContentAccessor) obj).getContent();
        for (Object child : children) {
            result.addAll(getAllElementFromObject(child, toSearch));
        }
    }
    return result;
}

public static void findAndReplace(WordprocessingMLPackage doc, String toFind, String replacer){
    List<Object> paragraphs = getAllElementFromObject(doc.getMainDocumentPart(), P.class);
    for(Object par : paragraphs){
        P p = (P) par;
        List<Object> texts = getAllElementFromObject(p, Text.class);
        for(Object text : texts){
            Text t = (Text)text;
            if(t.getValue().contains(toFind)){
                t.setValue(t.getValue().replace(toFind, replacer));
            }
        }
    }
}

希望这可以帮助。

于 2013-05-23T10:37:10.513 回答
1

Sun/Oracle JAXB 中的 XPath 内容包含许多已知缺陷,这使得它在实践中的用处不如其承诺。

我不使用它。相反,我使用类似的东西:

    static class PFinder extends CallbackImpl {

            List<P> paragraphList = new ArrayList<P>();  

            @Override
            public List<Object> apply(Object o) {

                    if (o instanceof P ) {
                          paragraphList .add((P)o);
                    }                      
                    return null;
            }
    }

            PFinder PFinder = new PFinder();
            new TraversalUtil(paragraphs, PFinder);

            for ( P p : pFinder.paragraphList ) { ...

你可以做类似的事情,寻找 w:t

或者,如果你真的想继续使用 XPath,你现在可以试试MOXy

更一般地说,我建议您考虑使用内容控制数据绑定,而不是您的字符串替换方法。在 docx4j 中,内容控制数据绑定提供了一系列优势,包括:

  • 重复材料(例如表格的行)
  • 有条件地包含/排除内容
  • 包含图像(base64 编码)
  • XHTML 内容的导入
于 2012-11-02T20:10:46.760 回答