Dev (Back & Front)ARTIGO

ODFDOM para Java: simplificando o controle programático de documentos e seus dados – Parte 02

O segundo de uma série de três partes, este artigo oferece informações
sobre a estrutura de código do Open Document Format (ODF) Document
Object Model (DOM) para Java. Apresentamos a arquitetura em camadas do
ODFDOM e as composições e funções de cada camada, incluindo o
relacionamento entre as camadas.

Visão geral do modelo em camadas ODFDOM

O ODFDOM para Java oferece uma API Java leve para desenvolvedores que
querem criar, acessar e salvar documentos ODF sem precisar obter
conhecimentos detalhados de toda a especificação ODF padrão.

O ODFDOM adota uma estrutura hierárquica em várias camadas, com cada
camada tendo uma finalidade específica. A camada inferior não tem
nenhuma dependência nas camadas superiores devido a um design de loose
coupling. A Figura 1 ilustra a estrutura hierárquica do modelo em
camadas ODFDOM.

Figura 1. Modelo em camadas ODFDOM

Essas camadas estão resumidas assim:

  • Camada expansível / documento ODF personalizado: de
    agora em diante, essa camada será denominada camada personalizada.
    Embora não faça parte do pacote ODFDOM, ela é projetada como uma camada
    em cima do ODFDOM, na qual os usuários podem sobrescrever ou
    personalizar a API ODFDOM existente para atender a um requisito
    específico.
  • Camada de funcionalidade conveniente / documento ODF: essa
    camada é, de agora em diante, denominada camada de conveniência e é o
    foco dos desenvolvedores, porque ela é baseada na camada DOM; dessa
    forma, ela fornece as APIs mais completas e utilizáveis para os usuários
    executarem operações de documentos.
  • Camada XML/DOM do tipo ODF: de agora em diante,
    essa camada é denominada camada DOM. A especificação e a gramática
    ODFDOM (esquema RelaxNG) definem todos os elementos e atributos XML ODF
    existentes possíveis e seu relacionamento nos fluxos XML ODF
    padronizados. Ou seja, todos os arquivos XML no pacote ODF (por exemplo,
    content.xml, styles.xml).
    A camada DOM fornece as informações necessárias relevantes aos
    elementos e atributos XML usados para construir o Document Object Model
    (DOM). Em vez de todas as classes dessa camada serem escritas de forma
    trabalhosa, elas são geradas automaticamente pela especificação ODF, de
    modo que essa camada possa ser facilmente alterada quando a
    especificação ODF for aprimorada e melhorada.

  • Camada física / pacote ODF: de agora em diante,
    essa camada é denominada camada de pacote neste artigo. Como a camada
    inferior da estrutura hierárquica ODFDOM, ela fornece acesso direto ao
    armazenamento físico no pacote ODF, como fluxos XML, imagens e objetos
    incorporados.

No restante deste artigo, analisamos a fundo cada camada para entender suas funções e seus relacionamentos em mais detalhes.

Camada de pacote ODFDOM

O nome da camada inferior ODFDOM surgiu da estrutura de documentos ODF.

Estrutura de documentos ODF

O documento ODFDOM é representado por um pacote de recursos nomeados
compactados em um pacote, o que é a maior diferença entre ele e outros
formatos de arquivos de documentos.

É possível alterar a extensão de documentos ODF para .zip; quando o
pacote é extraído, são obtidos fluxos de arquivo como content.xml,
styles.xml, settings.xml, meta.xml, mimetype, manifest.xml e uma imagem
mencionada no documento ODF (consulte a figura 2).

Figura 2. Estrutura de documentos ODF

Todos os tipos de documentos ODF têm essa mesma estrutura de
arquivos, e alguns documentos ODF completos podem também incluir objetos
OLE no pacote. Na Figura 2, todos os fluxos, exceto a pasta Pictures e
seu conteúdo, são especificados pelo padrão ODF e estão definidos assim:

  • Mimetype: especifica
    o tipo de documento ODF; os ODFs mais comuns são documentos de texto,
    planilha e apresentação. Mesmo se a extensão de arquivo do documento ODF
    não estiver correta, você poderá identificar facilmente o tipo de
    documento extraindo esse arquivo.
  • content.xml, styles.xml, meta.xml e settings.xml: especifica
    o conteúdo do documento atual, incluindo conteúdo de texto, imagens,
    estilos aplicados ao conteúdo e metainformações de documentos. Esses
    quatro esquemas de arquivo XML são restritos pela especificação ODF,
    incluindo o contexto de elementos, o relacionamento entre elementos e
    atributos e o conjunto de valores dos atributos. É possível acessar facilmente esses elementos por meio da API da camada DOM apresentada na próxima seção.

  • META-INF\manifest.xml: relaciona todas as entradas
    de arquivo no pacote ODF. Cada entrada de arquivo contém o nome do
    arquivo, o tipo e as informações de criptografia. Essa gramática de
    arquivo XML é também definida pelo esquema ODF Manifest.

Funções de camada de pacote

A camada de pacote faz o seguinte:

  • Manipula documentos na camada de pacote que lidam diretamente com o armazenamento físico: essa manipulação inclui a obtenção de um determinado fluxo de entrada
    de arquivo do pacote de documentos, a atualização, a inserção ou a exclusão
    de um fluxo de arquivos e outras operações básicas. Essa camada fornece a base para que API da camada de conveniência
    abra, salve ou modifique o documento ODF, além de liberar a camada de
    conveniência para trabalhar somente com operações de camada de documento
    em vez de atividades de camada de pacote.

  • Cuida do analisador e da construção do META-INF\manifest.xml: a camada de pacote não só lê e grava os fluxos XML, como também manipula o
    conteúdo de META-INF\manifest.xml. De acordo com o esquema ODF
    Manifest, esse arquivo lista todos os fluxos de arquivo contidos no
    pacote ODF. A camada de pacote é também responsável por analisar e por construir o
    arquivo manifest.xml e por atualizar esse arquivo quando uma imagem tiver
    sido inserida ou outros fluxos de arquivo tiverem sido alterados. Se um documento ODF tiver sido criptografado ou assinado
    digitalmente, o arquivo manifest.xml não será criptografado; ele
    preservará a chave e a compilação de cada fluxo de arquivo
    criptografado. Atualmente, o ODFDOM não oferece suporte a essa função.

  • Realiza carregamento lento: na
    importação de um documento ODF, nem todos os fluxos de arquivo do
    pacote precisam ser carregados na memória. Por exemplo, se você quiser
    adicionar apenas uma frase ao documento de texto ODF, dois fluxos de
    arquivo (content.xml e META-INF/manifest.xml) precisarão ser
    modificados, portanto somente esses dois arquivos são carregados sob
    demanda.
    A camada de pacote lê o fluxo de arquivo carregado e, se estiver no
    formato XML, a camada DOM analisará o fluxo de acordo com a
    especificação ODF e construirá a árvore DOM na memória. Após um usuário modificar o documento usando a API da camada de
    conveniência, a operação de salvar é acionada, e a camada de pacote
    transforma o DOM do conteúdo modificado em um fluxo de saída,
    sobrescrevendo o content.xml original e atualizando o manifest.xml. A camada de pacote pode ser usada sozinha, independentemente das
    camadas superiores, e os usuários podem modificar o documento ODF no
    nível de fluxo ou pacote.

A Listagem 1 mostra um exemplo simples de uma API de camada de pacote
que insere uma imagem no pacote sample.odt. Observe que esse código de
amostra simplesmente insere a imagem no pacote ODF em vez de inserir a
referência da imagem no conteúdo do documento.

Listagem 1. Código para inserir uma imagem no pacote ODF (API da camada de pacote)

import org.odftoolkit.odfdom.pkg.OdfPackage;<br />[...]<br /><br />// loads the ODF document package from the path<br />OdfPackage pkg = OdfPackage.loadPackage("C:\sample.odt");<br /><br />// loads the image from the URL and inserts the image in the package, <br />pkg.insert(new URI("C:\helloWorld.png"), "Pictures/helloWorld.png", "image/png");<br /><br />// save it including adapting the manifest<br />pkg.save("C:\sample.odt");

É possível obter todo o código de origem da implementação da camada de
pacote no pacote Java ODFDOM chamado org.odftoolkit.odfdom.pkg.*.

Camada ODFDOM DOM

Como um formato de documento padronizado, a especificação ODF é
desenvolvida pela organização de desenvolvimento de padrões OASIS. Os
aplicativos que implementam corretamente a especificação ODF podem
interoperar e trocar seus arquivos ODF com outros aplicativos.

Todos os arquivos XML podem ser acessados por meio da API DOM W3C,
que cria uma árvore DOM residente na memória composta por todos os nós
XML desse arquivo. Com a API DOM W3C, os usuários podem adicionar e
remover facilmente os nós ou modificar o atributo desse nó nessa árvore.

Entretanto, observe que, nessa camada, somente os arquivos XML padronizados ODF podem ser construídos como a árvore ODFDOM.

Funções da camada DOM

A camada DOM é responsável por analisar e construir os arquivos XML
no pacote ODF, exceto o arquivo manifest.xml, que opera na camada de
pacote. Através da análise, uma árvore DOM residente na memória pode ser
construída com os nós DOM inseridos, com cada nó correspondendo a uma
classe de camada DOM que representa o elemento ou o atributo XML ODF.

A definição dessas classes é feita pela especificação ODF. Se o nó
XML não estiver definido pela especificação ODF, a classe
org.odftoolkit.odfdom.pkg.element.OdfAlienElement/
org.odftoolkit.odfdom.pkg.element.OdfAlienAttribute será construída.

Essa classe é usada para representar os nós XML externos, que
permanecem no modelo de documento e não são negligenciados. Quando a
árvore ODF DOM é modificada, o valor do nó XML é também definido em cada
classe de implementação.

A camada DOM fornece uma base para a construção da árvore DOM
compatível com a especificação padrão ODF. Essa conformidade assegura a
boa interoperabilidade entre o ODFDOM e outros aplicativos ODF.

A API da camada DOM é também independente da camada superior, portanto é possível usar essa camada para modificar a árvore DOM.

Composição da camada DOM

Todas as origens da camada DOM são organizadas no pacote
org.odftoolkit.odfdom.dom.*. Atualmente, o ODFDOM é compatível com o
esquema ODF 1.2 mais recente. Ele contém 599 classes de elementos e 1301
classes de atributos, e todas implementam a interface org.w3c.dom.Node
da API DOM W3C, a fim de garantir que cada atributo e elemento XML possa
representar o nó DOM.

O caminho de pacote dessas classes de elementos e atributos depende
do espaço de nomes do nó XML, cujo nome é composto pelo uso do espaço de
nomes, do nome local e do tipo de nó (consulte a Listagem 2).

Listagem 2. Exemplo de fragmento de código da especificação ODF

<define name="table-table"><br />	<element name="table:table"><br />		<ref name="table-table-attlist"/><br />		<optional><br />			<ref name="table-title"/><br />		</optional><br />		<optional><br />			<ref name="table-desc"/><br />		</optional><br />		<optional><br />			<ref name="table-table-source"/><br />		</optional><br />		<optional><br />			<ref name="office-dde-source"/><br />		</optional><br />		<optional><br />			<ref name="table-scenario"/><br />		</optional><br />		<optional><br />			<ref name="office-forms"/><br />		</optional><br />		<optional><br />			<ref name="table-shapes"/><br />		</optional><br />		<ref name="table-columns-and-groups"/><br />		<ref name="table-rows-and-groups"/><br />	</element><br /></define><br />????<br /><define name="table-table-attlist" combine="interleave"><br />	<optional><br />		<attribute name="table:name"><br />			<ref name="string"/><br />		</attribute><br />	</optional><br /></define>

A Listagem 2 extrai um fragmento da especificação ODF que define um
elemento chamado <table:table>, portanto o caminho de classe desse
elemento é org.odftoolkit.odfdom.dom.table.TableTableElement.

A referência table-table-attrlist define o atributo table:name desse
elemento <table:table>, portanto o caminho de classe do atributo é
org.odftoolkit.odfdom.dom.TableNameAttribute.

Cada classe de elemento é uma classe abstrata derivada de
org.odftoolkit.odfdom.OdfElement, e cada classe fornece métodos para
obter e definir seus próprios atributos e criar seus elementos-filhos
permitidos, que são totalmente definidos pela especificação ODF.

A Listagem 3 mostra uma parte dos métodos da classe org.odftoolkit.odfdom.dom.table.TableTableElement.

Listagem 3. Fragmento de código org.odftoolkit.odfdom.dom.table.TableTableElement

/**<br />* Receives the value of the ODFDOM attribute representation <br /><code>TableNameAttribute</code> , See {@odf.attribute table:name}<br />*<br /> * @return - the <code>String</code> , the value or <code>null<br /> </code>, if the attribute is not set and no default value defined.<br />*/<br />public String getTableNameAttribute()<br />{<br />TableNameAttribute attr = (TableNameAttribute) getOdfAttribute<br />(OdfName.get<br />(OdfNamespace.get(OdfNamespaceNames.TABLE), "name" ) );<br />if( attr != null ){<br />return String.valueOf( attr.getValue() );<br />}<br />return null;<br />}<br /><br />/**<br /> * Sets the value of ODFDOM attribute representation <code><br /> TableNameAttribute</code> , See {@odf.attribute table:name}<br />*<br /> * @param tableNameValue   The type is <code>String</code><br /> */<br />public void setTableNameAttribute( String tableNameValue )<br />{<br />TableNameAttribute attr =  new TableNameAttribute( <br />(OdfFileDom)this.ownerDocument );<br />setOdfAttribute( attr );<br />attr.setValue( tableNameValue );<br />}<br />????<br />/**<br /> * Create child element {@odf.element table:table-row}.<br /> *<br /> * @return   return  the element {@odf.element table:table-row}<br /> * DifferentQName <br /> */<br />public TableTableRowElement newTableTableRowElement()<br />{<br />TableTableRowElement  tableTableRow = <br />((OdfFileDom)this.ownerDocument).newOdfElement<br />(TableTableRowElement.class);<br />this.appendChild( tableTableRow);<br />return  tableTableRow;<br />}

O pai de uma classe de atributo é org.odftoolkit.odfdom.OdfAttribute, e
toda classe de atributo especifica o tipo de valor e o valor padrão de
seus elementos. O tipo de valor de alguns atributos faz referência ao
tipo de dado definido pela W3C, portanto ao implementar esses tipos de
dados no pacote org.odftoolkit.odfdom.type.*, podemos verificar com
facilidade o valor do atributo.

Geração de código da camada DOM

O ODF 1.2 é a versão mais recente do padrão. O ODF Technical
Committee assegura que o esquema ODF seja mantido, atualizado e
aprimorado regularmente, exigindo que as classes de camada DOM sejam
também atualizadas quando o esquema mudar.

Devido ao grande tamanho da especificação ODF, é impossível atualizar
as classes da camada DOM manualmente, portanto nós as geramos com o
esquema ODF. Essa geração automática garante a cobertura completa e
precisa da especificação ODF e a fácil atualização para versões futuras
do ODF.

Os usuários podem executar o comando mvn -P codegen no diretório raiz
do projeto ODFDOM para gerar todo o código de origem da camada DOM em
até 20 segundos.

No momento, a geração de código é um projeto independente separado do projeto ODFDOM. É
possível acessar a página wiki do ODFDOM para fazer o download do código de origem do
ODFDOM e do projeto de geração de código.
http://odftoolkit.org/projects/odfdom/pages/Home

A execução do arquivo de execução de geração de código requer quatro
parâmetros, que são todos configurados no arquivo pom.xml do projeto
ODFDOM (consulte a Listagem 4).

Listagem 4. Configuração de parâmetro da geração de código

<configuration><br /><sourceRoot>${basedir}/src/main/java</sourceRoot><br /><schemaFile>${basedir}/src/codegen/resources/dom/<br />OpenDocument-schema-v1.2-cd02-rev02.rng</schemaFile><br /><configFile>${basedir}/src/codegen/resources/dom/config.xml</configFile><br /><templateFile>${basedir}/src/codegen/resources/dom/<br />javacodetemplate.xml</templateFile><br /></configuration>

em que:

  • Parâmetro 1: sourceRoot aponta para o destino do código de origem gerado.
  • Parâmetro 2: schemaFile especifica o local do
    esquema ODF. Os usuários podem substituir qualquer versão do arquivo de
    esquema para obter o código de camada DOM correspondente.
  • Parâmetro 3: configFile relaciona a classe base e a
    família de alguns elementos XML, o valor padrão de atributos (porque o
    arquivo de esquema do parâmetro 2 não contém o valor padrão, mas é
    definido na especificação ODF) e a implementação de classe dos tipos de
    dados definidos pela W3C.
  • Parâmetro 4: templateFile define o modelo de cada classe de elemento e atributo gerada.

Camada de conveniência do ODFDOM

Nas seções anteriores, aprendemos que a camada de pacote pode obter
um fluxo do pacote ODF, a camada DOM pode criar e operar a árvore DOM
livremente e então o fluxo modificado pode ser salvo novamente no
pacote.

Operar nos elementos e atributos especificados pelo ODF para
manipular os documentos pode ser um processo complexo para
desenvolvedores, especialmente se eles não estiverem familiarizados com a
especificação ODF e o analisador de XML.

Objetivos da camada de conveniência

A API da camada de conveniência, uma interface de programação de
usabilidade mais alta, foi projetada para cenários de operação de
documentos frequentemente usados. Sem manipular a árvore DOM, os
usuários podem escrever uma quantidade mínima de código de origem para
executar uma série de operações de documento, como inserir uma tabela,
atualizar um gráfico em um documento e até mesmo copiar e colar textos
entre documentos diferentes.

Além disso, os usuários não precisam se preocupar com o conteúdo
específico do fluxo de arquivos no pacote ODF. A API da camada de
conveniência implementa um conjunto de APIs para cada recurso de
documento, e um recurso pode lidar com vários elementos XML.

É possível imaginar o quão conveniente é o fato de que precisamos de
apenas três linhas para criar uma tabela: abra o documento, insira uma
tabela em alguma posição e salve-o.

Funções da camada de conveniência

Aqui, apresentamos algumas funções principais da camada de conveniência:

  • Operação em nível de documento. Ao
    contrário do nível de pacote, o nível de documento pode criar e salvar
    tipos diferentes de documentos ODF (arquivos .odt, .odp, .ods) e também
    integrar um documento a outro documento.
  • Camada de conveniência e relacionamento de mapeamento da camada DOM. Em
    geral, uma classe de conveniência é derivada da classe de elemento da
    camada DOM correspondente para herdar a funcionalidade DOM. O nome da
    classe de conveniência é similar ao da classe-pai, mas com o novo
    prefixo “Odf” e o sufixo “Element” omitido. Por exemplo, no caso do elemento <draw:frame>, o nome de classe
    da camada DOM é org.odftoolkit.odfdom.dom.element.draw.DrawFrameElement, e a classe da
    camada de conveniência tem o nome org.odftoolkit.odfdom.doc.draw.OdfDrawFrame. Mas esse design parece entrar em conflito com o objetivo da camada de
    conveniência, que é voltar o foco para o recurso, onde um recurso pode
    controlar vários elementos XML. Como resultado, podemos optar por
    refatorar a API da camada de conveniência usando um padrão de design de
    delegação em vez de herança. Em outras palavras, cada recurso da camada de conveniência delega e
    organiza as classes de elemento relacionadas da camada DOM para
    implementar a API da camada de conveniência. Por exemplo, no recurso de tabela, usado para inserir, excluir ou
    modificar a tabela do documento, os relacionamentos de herança 1:1 entre
    as classes da camada de conveniência e as classes da camada DOM foram
    rompidos, portanto relacionamentos compostos são usados. Dessa forma, a classe de recurso de tabela usa a classe do elemento
    DOM chamada org.odftoolkit.odfdom.dom.element.table.TableTableElement
    como o membro da classe.

  • APIs de conveniência. O
    ODFDOM versão 0.8 foi lançado em 19 de fevereiro de 2010. Ele adiciona
    muitas APIs de camada de conveniência empolgantes, incluindo a API de
    navegação de texto, com as quais os usuários podem manipular o texto,
    imagens, recursos de tabela e procurar e substituir o conteúdo do texto
    com facilidade. Além disso, um pacote incubador foi adicionado para a navegação pelo
    documento de texto ODF, oferecendo uma função que pesquisa os textos de
    acordo com padrões ou estilos de texto e executa operações no texto
    selecionado.

Todas as origens da camada de conveniência são organizadas no pacote org.odftoolkit.odfdom.doc.*.

Conclusão

A API ODFDOM emprega uma abordagem de camadas para acessar documentos.
Este artigo apresentou as composições e as funções das camadas e o
relacionamento entre camadas adjacentes. Os usuários têm a flexibilidade
de trabalhar em camadas diferentes de acordo com as suas necessidades.

Recursos

Aprender

Discutir

***

artigo publicado originalmente no developerWorks Brasil, por Wei Hua Wang


Wei Hua Wang é uma Software Engineer do IBM China Development Lab, onde é
membro do Lotus Symphony Team. Concentrando-se principalmente no
desenvolvimento da interoperabilidade ODF, ela é também membro da equipe
de desenvolvimento IBM da comunidade de software livre do ODF Toolkit. É
possível entrar em contato com ela através do e-mail
weihuaw@cn.ibm.com.

é o portal de tecnologia da IBM para profissionais de TI de todo o mundo. Colabore, aprenda a criar aplicativos inovadores e compreenda tecnologias avançadas. Acesse mais artigos e tutoriais em www.ibm.com/developerworks/br

Ver perfil