Introdução ao Docx4J

Introdução ao Docx4J

1. Visão geral

Neste artigo, focaremos na criação de um documento .docx usando a biblioteca https://www.docx4java.org [docx4j].

O Docx4j é uma biblioteca Java usada para criar e manipular arquivos Office OpenXML - o que significa que só pode funcionar com o tipo de arquivo .docx, enquanto as versões anteriores do Microsoft Word usam uma extensão .doc (arquivos binários).

*Observe que o formato _OpenXML_ é suportado pelo Microsoft Office, começando com a versão 2007.*

*2. Configuração do Maven *

Para começar a trabalhar com o docx4j, precisamos adicionar a dependência necessária em nosso pom.xml:

<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j</artifactId>
    <version>3.3.5</version>
</dependency>
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.1</version>
</dependency>

Observe que sempre podemos procurar as versões mais recentes das dependências em https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.docx4j%22%20AND%20a%3A%22docx4j% 22 [Maven Central Repository].

A dependência JAXB é necessária, pois o docx4j usa essa biblioteca sob o capô para organizar/desmarcar partes XML em um arquivo docx.

===* 3. Crie um documento de arquivo Docx *

====* 3.1 Elementos de texto e estilo *

Vamos primeiro ver como criar um arquivo docx simples - com um parágrafo de texto:

WordprocessingMLPackage wordPackage = WordprocessingMLPackage.createPackage();
MainDocumentPart mainDocumentPart = wordPackage.getMainDocumentPart();
mainDocumentPart.addStyledParagraphOfText("Title", "Hello World!");
mainDocumentPart.addParagraphOfText("Welcome To Baeldung");
File exportFile = new File("welcome.docx");
wordPackage.save(exportFile);

Aqui está o arquivo welcome.docx resultante:

link:/wp-content/uploads/2017/10/im1.png [imagem:/wp-content/uploads/2017/10/im1-300x236.png [imagem, largura = 554, altura = 436]]

Para criar um novo documento, precisamos usar o WordprocessingMLPackage, que representa um arquivo docx no formato OpenXML, enquanto a classe MainDocumentPart mantém uma representação da parte principal document.xml.

Para esclarecer as coisas, descompacte o arquivo welcome.docx e abra o arquivo word/document.xml para ver como é a representação XML:

<w:body>
    <w:p>
        <w:pPr>
            <w:pStyle w:val="Title"/>
        </w:pPr>
        <w:r>
            <w:t>Hello World!</w:t>
        </w:r>
    </w:p>
    <w:p>
        <w:r>
            <w:t>Welcome To Baeldung!</w:t>
        </w:r>
    </w:p>
</w:body>

Como podemos ver,* cada frase é representada por uma sequência (r) de texto (t) dentro de um parágrafo (_p _) *, e é para isso que serve o método _addParagraphOfText () _.

O addStyledParagraphOfText () _ faz um pouco mais do que isso; ele cria propriedades de parágrafo (_pPr) que mantém o estilo a ser aplicado ao parágrafo.

Simplificando, os parágrafos declaram execuções separadas e cada execução contém alguns elementos de texto:

link:/wp-content/uploads/2017/10/p-r-t.png [imagem:/wp-content/uploads/2017/10/p-r-t.png [imagem, largura = 385, altura = 240]]

Para criar um documento bonito, precisamos ter controle total desses elementos _ (parágrafo, execução, _ e texto) .

Então, vamos descobrir como estilizar nosso conteúdo usando o objeto runProperties (RPr):

ObjectFactory factory = Context.getWmlObjectFactory();
P p = factory.createP();
R r = factory.createR();
Text t = factory.createText();
t.setValue("Welcome To Baeldung");
r.getContent().add(t);
p.getContent().add(r);
RPr rpr = factory.createRPr();
BooleanDefaultTrue b = new BooleanDefaultTrue();
rpr.setB(b);
rpr.setI(b);
rpr.setCaps(b);
Color green = factory.createColor();
green.setVal("green");
rpr.setColor(green);
r.setRPr(rpr);
mainDocumentPart.getContent().add(p);
File exportFile = new File("welcome.docx");
wordPackage.save(exportFile);

Aqui está a aparência do resultado:

link:/wp-content/uploads/2017/10/im2a.png [imagem:/wp-content/uploads/2017/10/im2a-300x236.png [imagem, largura = 461, altura = 363]]

Depois de criar um parágrafo, uma execução e um elemento de texto usando createP () _, _createR () _ e _createText () _ respectivamente, declaramos um novo objeto _runProperties (RPr) para adicionar um pouco de estilo ao elemento de texto .

O objeto rpr é usado para definir propriedades de formatação, Negrito (B), Itálico (I) e maiúsculo (Caps); essas propriedades são aplicadas ao texto executado usando o método _setRPr () _.

3.2 Trabalhando com imagens

O Docx4j oferece uma maneira fácil de adicionar imagens ao nosso documento do Word:

File image = new File("image.jpg" );
byte[] fileContent = Files.readAllBytes(image.toPath());
BinaryPartAbstractImage imagePart = BinaryPartAbstractImage
  .createImagePart(wordPackage, fileContent);
Inline inline = imagePart.createImageInline(
  "Baeldung Image (filename hint)", "Alt Text", 1, 2, false);
P Imageparagraph = addImageToParagraph(inline);
mainDocumentPart.getContent().add(Imageparagraph);

E aqui está a aparência da implementação do método _addImageToParagraph () _:

private static P addImageToParagraph(Inline inline) {
    ObjectFactory factory = new ObjectFactory();
    P p = factory.createP();
    R r = factory.createR();
    p.getContent().add(r);
    Drawing drawing = factory.createDrawing();
    r.getContent().add(drawing);
    drawing.getAnchorOrInline().add(inline);
    return p;
}

Primeiro, criamos o arquivo que contém a imagem que queremos adicionar à parte principal do documento e, em seguida, vinculamos a matriz de bytes que representa a imagem ao objeto wordMLPackage.

Depois que a parte da imagem é criada, precisamos criar um objeto Inline usando o método createImageInline ().

O método addImageToParagraph () _ incorpora o objeto _Inline em um Drawing para que possa ser adicionado a um run.

Por fim, como um parágrafo de texto, o parágrafo que contém a imagem é adicionado ao mainDocumentPart.

E aqui está o documento resultante:

link:/wp-content/uploads/2017/10/im3a.png [imagem:/wp-content/uploads/2017/10/im3a-298x300.png [imagem, largura = 508, altura = 511]]

3.3 Criando tabelas

O Docx4j também facilita bastante a manipulação de Tabelas (Tbl), linhas (Tr) e colunas (Tc).

Vamos ver como criar uma tabela 3 × 3 e adicionar algum conteúdo a ela:

int writableWidthTwips = wordPackage.getDocumentModel()
  .getSections().get(0).getPageDimensions().getWritableWidthTwips();
int columnNumber = 3;
Tbl tbl = TblFactory.createTable(3, 3, writableWidthTwips/columnNumber);
List<Object> rows = tbl.getContent();
for (Object row : rows) {
    Tr tr = (Tr) row;
    List<Object> cells = tr.getContent();
    for(Object cell : cells) {
        Tc td = (Tc) cell;
        td.getContent().add(p);
    }
}

Dadas algumas linhas e colunas, o método createTable () _ cria um novo objeto _Tbl, o terceiro argumento refere-se à largura da coluna em twips (que é uma medida de distância - 1/1440 de polegada).

Uma vez criado, podemos iterar sobre o conteúdo do objeto tbl e adicionar objetos Paragraph em cada célula.

Vamos ver como é o resultado final:

link:/wp-content/uploads/2017/10/im4a.png [imagem:/wp-content/uploads/2017/10/im4a-300x236.png [imagem, largura = 609, altura = 479]]

*4. Lendo um documento de arquivo Docx *

Agora que descobrimos como usar o docx4j para criar documentos, vamos ver como ler um arquivo docx existente e imprimir seu conteúdo:

File doc = new File("helloWorld.docx");
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
  .load(doc);
MainDocumentPart mainDocumentPart = wordMLPackage
  .getMainDocumentPart();
String textNodesXPath = "//w:t";
List<Object> textNodes= mainDocumentPart
  .getJAXBNodesViaXPath(textNodesXPath, true);
for (Object obj : textNodes) {
    Text text = (Text) ((JAXBElement) obj).getValue();
    String textValue = text.getValue();
    System.out.println(textValue);
}

Neste exemplo, criamos um objeto WordprocessingMLPackage com base em um arquivo helloWorld.docx existente, usando o método _load () _.

Depois disso, usamos uma expressão XPath (//w: t) para obter todos os nós de texto da parte principal do documento.

O método getJAXBNodesViaXPath () _ retorna uma lista de objetos _JAXBElement.

Como resultado, todos os elementos de texto dentro do objeto mainDocumentPart são impressos no console.

Observe que sempre podemos descompactar nossos arquivos docx para entender melhor a estrutura XML, o que ajuda na análise de problemas e fornece uma melhor compreensão de como enfrentá-los.

===* 5. Conclusão*

Neste artigo, descobrimos como o docx4j facilita a execução de operações complexas no documento MSWord, como a criação de parágrafos, tabelas, partes de documentos e adição de imagens.

Os trechos de código podem ser encontrados, como sempre, over no GitHub.