Português::XMLnoPostgreSQL

From PostgreSQL wiki
Jump to navigationJump to search

Texto com necessidade de melhorar o conteúdo

XML no PostgreSQL

É possível integrar documentos XML e uma base relacional como o PostgreSQL, criando bases de dados híbridas. Já me deparei com situações em que o modelo relacional puro seria extremamente ineficiente e achei uma solução utilizando documentos XML dentro da base relacional. Além disso, estão surgindo aplicações de gerenciamento de documentos XML, que podem ter como base de dados um banco relacional. O suporte ao XML no PostgreSQL é feito com uma extensão presente no diretório contrib/xml. É um trabalho baseado em uma biblioteca de funções para manipulação de XML e de consultas XPath (uma linguagem de consulta para documentos XML) já existente chamada libxml. A extensão provê basicamente duas funcionalidades ao PostgreSQL:

  1. Validar documentos XML com base em um DTD (através da função pgxml_parse);
  2. Fazer consultas XPath nos documentos armazenados (através da função pgxml_xpath).

Essas duas funcionalidades são fundamentais quando se utiliza armazenamento de documentos XML na base de dados.

Instalação

O primeiro passo para utilizar as duas funções é instalar o módulo xml. Para compilar os fontes do módulo xml, independente de qual plataforma seja utilizada, é necessário baixar os fontes da libxml. Para isso basta entrar no site ftp://xmlsoft.org/, copiar o arquivo (libxml2-2.5.6.tar.gz ou a versão mais recente) e extrair os arquivos .h da pasta include para um diretório criado por você com o nome de libxml dentro de contrib/xml.

cd diretorio_fontes_postgresql/contrib/xml
gmake
gmake install

Observação

É importante observar que o pacote RPM postgresql-contrib do RedHat não instala esse módulo (pelo menos até o RedHat 8). Algumas versões do PostgreSQL, quando instaladas a partir do ports do FreeBSD já vêm com os arquivos da libxml. Depois de instalar o módulo, é preciso executar os comandos SQL contidos no arquivo pgxml.sql para criar as funções na base de dados em que você vai utilizá-las.

Utilização

Com a primeira função, a pgxml_parse, podemos nos certificar de que o documento XML é coerente com a sua definição (o seu DTD), e assim podemos fazer consultas XPath tranquilamente no documento, além de manter a base íntegra. Essa função torna possível a criação de uma regra de validação de XML na inserção da linha que contém o documento. A função a seguir poderia ser utilizada para validar o conteudo de um documento contido na tabela "documentos" com o seu DTD que está na tabela "formatos":

CREATE OR REPLACE FUNCTION validaXML(int4, int4) RETURNS bool AS
'
SELECT pgxml_parse((SELECT dtd FROM formatos WHERE formatos.codformato = $2) || CONVERT(documentos.conteudo, ''LATIN1'', ''UNICODE'')) 
FROM documentos WHERE documentos.coddocumento = $1;
'
LANGUAGE 'sql';

Na função acima, o código do documento é passado como primeiro parâmetro, e o segundo é o código do formato (que indica qual DTD usar na validação), e a função "CONVERT" é utilizada para converter a codificação do documento para UNICODE, pois as funções de manipulação de XML só trabalham com UNICODE. Além disso, seria possível criar até um tipo de dados específico para armazenar XMLs, que faça essas verificações automaticamente, mas não vou me aprofundar nesse ponto, pois daria outro artigo inteiro. A segunda função, a pgxml_xpath, possibilita a extração de dados específicos de dentro do documento XML consultado. Por exemplo, você utiliza um campo que armazena documentos XML representando as especificações técnicas de um determinado produto. Digamos que essa tabela de produtos tenha a seguinte estrutura:

CREATE TABLE Produtos (
id_produto Serial,
id_tipo_produto,
nome varchar(50),
descricao text,
especificacoes_tecnicas text);

No campo especificacoes_tecnicas é inserido um documento XML contendo todas as especifiações do produto. Esse XML poderia ser assim:

<especificacoes>
<medidas>
<peso>
13 Kg
</peso>
<altura>
1,77 m
</altura>
<largura>
1,50 m
</largura>
</medidas>
</especificacoes>

Caso eu queira listar todos os produtos do tipo 1 e seus respectivos pesos eu poderia usar um SQL com a função XPath:

SELECT nome, pgxml_xpath(string_contendo_dtd || especificacoes_tecnicas, '//especificacoes/medidas/peso/text()','','') as peso
FROM Produtos
WHERE id_tipo_produto = 1;

Nesse caso, eu concatenei manualmente uma string contendo o DTD do documento XML no primeiro parâmetro da função, que deve receber o documento XML a ser processado. No segundo parâmetro, eu passei uma string especificando a busca a ser realizada dentro do XML, no caso: //especificacoes/medidas/peso/text() o que significa que eu quero o texto do item peso dentro do item medidas dentro de especificacões. As duas barras (//) no início da string indicam que todos os itens filhos devem ser processados (no caso, todos os filhos de "especificacoes"), e o text() no fim da string significa que eu quero retornar somente o conteúdo do item peso (segundo o exemplo, seria: "13 Kg") e não o item inteiro (que seria: " 13 Kg "). Poderíamos usar um documento um pouco mais complexo para explorar melhor o potencial do XPath, aproveitemos o exemplo anterior e vamos acrescentar atributos a alguns itens do XML:

<especificacoes>
<medidas>
<peso unidade="kg">
13 kg
</peso>
<peso unidade="lbs">
28,7 lbs
</peso>
<altura>
1,77 m
</altura>
<largura>
1,50 m
</largura>
</medidas>
</especificacoes>

Agora, digamos que eu queira o mesmo retorno do exemplo anterior (produtos do tipo 1 e seus respectivos pesos), mas dessa vez eu quero filtrar os itens peso, para que ele me traga somente aqueles que estiverem em libras:

SELECT nome, pgxml_xpath(string_contendo_dtd || especificacoes_tecnicas, '//especificacoes/medidas/peso[@unidade=''lbs'']/text()','','') as peso

FROM Produtos WHERE id_tipo_produto = 1;

Claro que os exemplos utilizados aqui são muito simplórios, mas devem ilustrar o potencial dessa ferramenta, pois assim como eu usei filtros em um determinado atributo, eu poderia usar uma série de outros recursos definidos pela linguagem XPath. Ainda seria possível utilizar funções que facilitem a busca por determinados grupos de informação, ou até funções que retornem o documento XML como uma outra tabela. Outra possibilidade interessante seria o armazenamento de objetos em formato xml na base de dados, de modo que eu possa fazer buscas nos objetos armazenados e instanciar o objeto diretamente de um campo do banco de dados. Além disso, existem várias outras possibilidades, é só uma questão de criatividade e estudo.

A especificação da liguagem XPath pode ser lida em: http://www.w3.org/TR/xpath

Um site onde existe uma boa documentação sobre XPath é o site da Microsoft sobre XPath:


Observação

Uma observação importante para quem pretende trabalhar com XML em PostgreSQL, é que as funções de XML só trabalham com textos codificados em UNICODE, e é importante observar o atributo encoding (codificação) do seu banco de dados. O encoding é definido no momento da criação do banco de dados no comando CREATE DATABASE. A codificação padrão, utilizada quando não se especifica nada no create database é definida no comando initdb. Caso ele não seja UNICODE, não se preocupe, o PostgreSQL tem uma função de conversão que pode ser utilizada para transformar campos de uma codificação em outra, a função convert:

convert('Texto', 'Codificação_Origem', 'Codificação_Destino')


XML com Java Persistence API (JPA)

Sabemos que mapeamentos objeto-relacional geralmente interferem de forma negativa em desempenho e até mesmo no uso correto do banco de dados. No entanto, essa técnica vem sendo utilizada cada vez com mais frenquencia pela sua alta produtividade durante o desenvolvimento de um software. O uso de frameworks para mapeamento objeto-relacional restringe o uso de diversas funcionalidades do banco de dados, como triggers, views, procedures e até mesmo o uso da coluna XML nativa do PostgreSQL. Entretanto, com algumas modificações no driver JDBC é possível realizar de forma transparente o mapeamento de colunas XML nativas. Na página do Driver JDBC4 com suporte a XML você encontra o link para download de um driver JDBC4 modificado que permite esse mapeamento. O driver possui licença de software livre e pode ser modificado e distribuído sem restrições.