ODFDOM para Java: Simplificando o controle programático de documentos e seus dados, Parte 2

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.

Wei Hua Wang, Software Engineer, IBM

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.



16/Abr/2010

Nota do editor: Você sabe muito sobre esse tópico? Deseja compartilhar seu conhecimento? Participe hoje do programa wiki do software IBM Lotus.

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
ODFDOM layered model

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
ODF document structure

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, inserção ou 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 alista todos os fluxos de arquivo contidos no pacote ODF.

    A camada de pacote é também responsável por analisar e construir o arquivo manifest.xml e 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;
[...]

// loads the ODF document package from the path
OdfPackage pkg = OdfPackage.loadPackage("C:\sample.odt");

// loads the image from the URL and inserts the image in the package, 
pkg.insert(new URI("C:\helloWorld.png"), "Pictures/helloWorld.png", "image/png");

// save it including adapting the manifest
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">
	<element name="table:table">
		<ref name="table-table-attlist"/>
		<optional>
			<ref name="table-title"/>
		</optional>
		<optional>
			<ref name="table-desc"/>
		</optional>
		<optional>
			<ref name="table-table-source"/>
		</optional>
		<optional>
			<ref name="office-dde-source"/>
		</optional>
		<optional>
			<ref name="table-scenario"/>
		</optional>
		<optional>
			<ref name="office-forms"/>
		</optional>
		<optional>
			<ref name="table-shapes"/>
		</optional>
		<ref name="table-columns-and-groups"/>
		<ref name="table-rows-and-groups"/>
	</element>
</define>
…………
<define name="table-table-attlist" combine="interleave">
	<optional>
		<attribute name="table:name">
			<ref name="string"/>
		</attribute>
	</optional>
</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
/**
* Receives the value of the ODFDOM attribute representation 
<code>TableNameAttribute</code> , See {@odf.attribute table:name}
*
 * @return - the <code>String</code> , the value or <code>null
 </code>, if the attribute is not set and no default value defined.
*/
public String getTableNameAttribute()
{
TableNameAttribute attr = (TableNameAttribute) getOdfAttribute
(OdfName.get
(OdfNamespace.get(OdfNamespaceNames.TABLE), "name" ) );
if( attr != null ){
return String.valueOf( attr.getValue() );
}
return null;
}

/**
 * Sets the value of ODFDOM attribute representation <code>
 TableNameAttribute</code> , See {@odf.attribute table:name}
*
 * @param tableNameValue   The type is <code>String</code>
 */
public void setTableNameAttribute( String tableNameValue )
{
TableNameAttribute attr =  new TableNameAttribute( 
(OdfFileDom)this.ownerDocument );
setOdfAttribute( attr );
attr.setValue( tableNameValue );
}
…………
/**
 * Create child element {@odf.element table:table-row}.
 *
 * @return   return  the element {@odf.element table:table-row}
 * DifferentQName 
 */
public TableTableRowElement newTableTableRowElement()
{
TableTableRowElement  tableTableRow = 
((OdfFileDom)this.ownerDocument).newOdfElement
(TableTableRowElement.class);
this.appendChild( tableTableRow);
return  tableTableRow;
}

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


Download

DescriçãoNomeTamanho
Código de amostraPart2-ODFDOM-Architecture.zip10KB

Recursos

Aprender

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Lotus
ArticleID=483310
ArticleTitle=ODFDOM para Java: Simplificando o controle programático de documentos e seus dados, Parte 2
publish-date=04162010