Construindo um DTD – Introdução ao XML - Parte VI

06 Apr 2009
8 mins read

Este post tem como objetivo mostrar como fazer a validação de um documento XML utilizando DTD. Os tópicos abordados são: introduzir a teoria básica do DTD.

Um DTD (Document Type Definition) especifica um conjunto de regras que define a estrutura de um documento.

O DTD pode aparecer no topo do XML (no prólogo) ou em um documento separado. Ter o DTD no topo do documento XML não tem nenhum problema se apenas um XML utilizar este DTD. Você vai ter um problema se vários documentos XML utilizarem o mesmo DTD, pois você vai precisar atualizar cada XML sempre que o DTD sofrer alterações. Uma solução é criar um arquivo externo ao XML que contém o DTD, e em cada XML fazer uma referência ao DTD.

Sintaxe de um DTD

Um DTD defini um documento XML da seguinte maneira:

O DTD pode ter uma declaração na primeira linha (assim como no XML - se for um documento externo). Nesta declaração, você pode definir a versão do XML e a codificação (ver introdução XML aqui). Quando você indica a codificação no DTD, não significa que o XML irá 'importar' essa configuração. Você deve especificar a codificação no XML também (e esta pode ser diferente do DTD).

Estrutura de um DTD

Como já foi dito acima, o DTD é um conjunto de regras, também chamadas de declarações. Cada declaração especifica um elemento, seus atributos, entidades e conteúdo. A figura abaixo exemplifica a estrutura de um DTD:

estrutura_dtd

A ordem da declaração dos elementos é importante em duas situações: A primeira, se houver declarações redundantes (atenção na hora de declarar o mesmo tipo de elemento duas vezes), o primeiro elemento declarado toma a precedência e todos os outros são ignorados. Essa informação é importante caso você vá sobrescrever declarações. A segunda, se entidades de parâmetro são utilizadas nas declarações, precisam ser declaradas antes de serem usadas como referências.

Declaração dos elementos do XML

A primeira e mais importante consideração na linguagem XML é o conjunto de elementos. Cada elemento que você for usar no documento XML deve ser declarado no DTD. Uma declaração de elemento faz duas coisas: adiciona um novo nome de elemento ao vocabulário da linguagem e documenta qual é o conteúdo desse elemento. Juntos (novo elemento + conteúdo), criam uma gramática para a linguagem, um padrão para determinar quais elementos são válidos.

A figura abaixo ilustra a estrutura de uma declaração, que é composta da String <!ELEMENT (1), seguida pelo nome do elemento declarado (2), o conteúdo (3) e o delimitador '>' (fechamento/fim da declaração).

declaracao_elemento_dtd

O nome do elemento é case-sensitive (o XML é case-sensitive, lembra?). O elemento Casa é diferente do elemento CASA ou casa. Por convenção, nome de elementos são sempre lowercase (letras minúsculas).

Um elemento XML pode conter cinco tipos diferentes de conteúdo:

1- Elementos vazios: a maneira mais simples de declarar um elemento vazio é através da palavra-chave EMPTY. Exemplo: <!ELEMENT grafico EMPTY>

2- Elementos que não contém restrições de conteúdo: neste tipo de declaração, o elemento XML pode conter qualquer outro elemento. Neste caso, é utilizada a palavra-chave ALL.
Exemplo: <!ELEMENT contem_qualquer_coisa ALL>

É claro que um elemento pode conter qualquer conteúdo limitado ao valor declarado no DTD, e neste tipo de modelo, não há controle da estrutura que um DTD mais rigoroso tem. Para rápida prototipação de documentos, este tipo pode ser interessante temporariamente.

3- Elementos que podem conter apenas dados do tipo texto (informação): Para elementos que apenas podem conter informação, mas não outros elementos, utiliza-se (#PCDATA), que significa "parsed-character data".Isso significa que os caracteres serão verificados por um parser XML à procura de referências de entidades, e caso houver alguma, então esta entidade será substituída por seu valor correspondente.

4- Elementos que podem contem apenas outros elementos: para declarar elementos dentro de um outro elemento, utiliza-se uma notação especial, descrita na lista abaixo:

Exemplos:

<!ELEMENT artigo (paragrafo+)>
<!ELEMENT artigo (titulo, (paragrafo | secao)+)>
<!ELEMENT artigo (
titulo, subtitulo?, ((paragrafo+, secao*) | secao+))>

5- Elementos com conteúdo misto: conteúdo misto é quando um elemento pode conter tanto elementos quanto informação. Um elemento desse tipo deve ser declarado como no exemplo abaixo:

A palavra chave ELEMENT deve vir primeiro, seguido do nome do elemento, e após este, a lista dos elementos permitidos e #PCDATA, separados por uma barra vertical ( | ), limitados por parênteses e finalmente, um asterisco ( * ).

Declaração dos atributos

Após declarar os elementos, você pode declarar os atributos. Para cada elemento, você geralmente declara todos os seus atributos em apenas um lugar. A estrutura pode ser conferida na estrutura abaixo:

declaracao_atributo_dtd

A declaração dos atributos começam com a string (7). Cada declaração de atributo consiste: no nome do atributo (4), seu repectivo valor (5), e a descrição do comportamento do atributo (6).

A declaração de um atributo faz três coisas: Primeiro, dá um nome ao atributo. Segundo, especifica o tipo do atributo, ou uma possível lista de valores que o atributo pode receber. E terceiro, descreve o comportamento do atributo: se existe um valor padrão, ou se é necessário (obrigatório) dar ao atributo um valor.

Tipos de atributos:

1- CDATA (character data)
Qualquer caracter pode ser usado, incluindo caracteres de entidades.
Declaração: <!ATTLIST circulo raio CDATA "12 cm">
Exemplos: dimensoes="35x12x9 mm" | expressao=" 5 + 7 = 3 * 4 "

2- NMTOKEN (name token)
Um name token é uma sequência de caracteres que começam com uma letra e pode conter números, letras e alguns caracteres de pontuação.
Exemplo: <!ATTLIST parte numero NMTOKEN #REQUIRED>
Obs.: qualquer espaço em branco (whitespace) é removido pelo processador XML.

3- ID (unique identifier)
Este tipo de atributo é especial, pois fornece ao atributo a garantiade ser único no documento. Dois elementos do XML não podem ter o mesmo valor de um atributo do tipo ID.
Exemplo: <!ATTLIST nome_id ID #REQUIRED>

4- IDREF (identifier reference)
Este tipo de atributo é similar ao tipo ID, mas em vez do valor do atributo se referir ao elemento em questão, refere-se ao ID de outro elemento. Se não existir nenhum elemento com o ID referenciado, o parser mostrará um erro. Este tipo é usado para fazer referência a relacionamentos.
Exemplo: <!ATTLIST relacionamento cliente ref IDREF #REQUIRED>

5- IDREFS(identifier reference list)
Uma lista separada por um espaço de valores de IDREF. Se não existir nenhum elemento com o ID referenciado, o parser mostrará um erro.
Exemplo: <!ATTLIST boxdvd refs IDREFS #REQUIRED>

6- ENTITY(nome de entidade)
Este tipo aceita um nome de entidade como valor. Você pode usá-lo após declarar uma entidade no DTD.
Exemplo: <!ATTLIST bulletlist icon ENTITY #IMPLIED>

<!ENTITY bluedot SYSTEM "icons/bluedot.png">

E assim seria o uso: <bulletlist icon="bluedot">

7- ENTITIES(lista de nomes de entidades)
O valor do atributo é uma lista de nomes de entidades separados por um espaço.
Exemplo: <!ATTLIST album filelist ENTITIES #REQUIRED>

8- Lista de valores Enumerados
Uma lista de valores enumerados é uma lista com palavras-chave que você define. Esse tipo de atributo é util quando se tem um conjunto pequeno de possibilidades de valores. Na declaração, você especifica a lista de valores cercada por parênteses, separados por barras verticais (|).
Exemplo: <!ATTLIST cliente genero ( F | M ) #IMPLIED>
Um atributo só pode ter um valor: <cliente genero="F">

9- NOTATION (lista de notações)
O valor de um atributo do tipo notação consiste em uma sequência de name tokens.
Uma notação pode ser definida para preservar espaços em um elemento que normalmente seriam removidos pelo parser.

Além dos tipos descritos acima, os atributos também podem ter os seguintes comportamentos:

- Valor padrão (default)
Se o usuário não colocar nenhum valor para determinado atributo, o processador XML assume o valor padrão indicado no DTD. Especificar um valor padrão para o atributo pode ser uma boa ideia se este valor é o mais comum.

- Atributo opcional
Quando você declara que um atributo pode ser opcional, o processador XML não atribui nenhum valor padrão, o atributo fica ausente.

- Atributo com valor obrigatório
O usuário deve fornecer um valor ao atributo, ou seja, o atributo não pode ser deixado em branco.

- Atributo de valor fixo
O usuário não pode modificar o valor desse atributo, esse tipo é utilizado para momentos em que você quer que o atributo sempre tenha o mesmo valor.

Como visto, os atributos podem conter várias particularidades e possuem bem mais detalhes que a declaração dos elementos. Por isso, você não precisa fazer todas as declarações de atributos para um elemento num só lugar. O XML permite que você faça várias declarações para um mesmo elemento, e na hora da execução é feito um 'merge'. Isso nos dá certa flexibilidade na hora de customizar o DTD. Se você quer adicionar declarações de atributos para um elemento que já exista no DTD, você pode criar uma nova declaração.

Conclusão

Neste post apenas a teoria foi apresentada. Não se preocupe, o próximo post será um exemplo prático de como construir um DTD.