8.2. Linguagem de Restrições

A questão pertinente do momento é: Como se irão especificar as restrições? Em que linguagem?

Como já foi discutido no capítulo anterior, há duas opções: desenvolver uma nova linguagem, ou, utilizar uma existente. Uma vez que o que se está a desenvolver é um protótipo e a escolha de uma linguagem existente pouparia algum trabalho, foi esta a opção escolhida.

Para se poder manipular elementos SGML e especificar restrições sobre eles a escolha natural seria uma linguagem de especificação baseada em modelos. Como já foi exemplificado na secção anterior e em [RAH95], cada definição de um elemento no DTD tem um modelo implícito e cada instância desse elemento pode ser convertida numa expressão algébrica desse modelo. No protótipo descrito mais à frente Figura 8-2, utiliza-se uma ferramenta de conversão automática, dtd2cam, para traduzir o DTD para um modelo na linguagem de especificação de SETs, CAMILA [ABNO97, BA95]. Depois desta conversão, o analista pode escrever as restrições em CAMILA uma vez que estas são naturalmente integradas no modelo calculado automaticamente a partir do DTD. Em termos práticos, cada restrição irá corresponder a um predicado que deverá sempre retornar o valor booleano verdade, caso contrário uma mensagem de erro terá de ser enviada ao utilizador.

Na nossa implementação, as restrições são especificadas por um conjunto de regras; cada regra, é um par formado por uma condição (a negação da respectiva restrição) e a reacção que lhe fica associada.

Os casos práticos trabalhados são de alguma complexidade e têm problemas muito específicos, o que os torna impróprios para exemplificar o sistema. Assim, recorre-se a um exemplo mais pequeno, com complexidade suficiente para ilustrar as ideias e o protótipo.


Exemplo 8-2. Reis e Decretos

Um documento é composto por uma lista de decretos proclamados por um determinado rei.

Apresenta-se a seguir o respectivo DTD:

<!DOCTYPE  rei  [
<!ELEMENT  rei    -- (nome, cognome, datan, 
                         datam,decreto+)>
<!ELEMENT  decreto -- (data, corpo)>
<!ELEMENT  (nome,cognome,datan,datam,data) 
              -- (#PCDATA)>

<!ATTLIST  (datan,datam,data)
    valor CDATA #IMPLIED
    tipo  CDATA #FIXED date>

<!ELEMENT  corpo   -- (#PCDATA)>
]>

Repare-se na declaração dos atributos tipo e valor para os elementos relacionados com datas. O atributo tipo tem um valor fixo que será usado mais tarde pelo processador de restrições (o validador semântico) para inferir o tipo do seu conteúdo. O atributo valor será utilizado para guardar a forma normalizada das datas; o processador usará o valor deste atributo, sempre que este estiver instanciado, em vez do conteúdo do elemento.

O texto seguinte é uma instância do referido documento, escrita de acordo com o DTD.

<rei>
  <nome>D.Dinis</nome>
  <cognome>O Lavrador</cognome>
  <datan valor='1270.09.23'>23 de Setembro de 
                               1270</datan>
  <datam valor='1370.09.23'>23 de Setembro de
                               1370</datam>
  <decreto>
    <data valor='1300.07.15'>Ao décimo quinto dia
      do mês de Agosto do ano 1300:</data>
    <corpo>A partir do dia de hoje, apenas 
      bicicletas poderão circular na cidade de 
      Braga.</corpo>
  </decreto>
  <decreto>
    <data>1389.11.03</data>
    <corpo>O McDonalds passará a vender vinho verde
      em vez de COCA-COLA.</corpo>
  </decreto>
</rei>

Observando o DTD e a respectiva instância pode-se identificar de imediato algumas condições que devem ser verificadas:

Para se adicionar estas condições de contexto ao nosso sistema de validação, adiciona-se ao DTD a declaração de entidades externas onde as condições estarão especificadas. Este método para associar restrições ao DTD representa apenas uma das três opções possíveis para o fazer e que são discutidas mais à frente (Secção 8.3).

<!DOCTYPE rei [
<!NOTATION CAM SYSTEM "camila.exe">
<!ELEMENT rei - - (nome,cognome,datan,datam,decreto+)>
<!ENTITY  rei-rest SYSTEM "rei.cam" NDATA CAM>
...
<!ELEMENT decreto - - (...)>
<!ENTITY  decreto-rest SYSTEM "decreto.cam" NDATA CAM>
]>

Neste caso, utiliza-se uma entidade para cada conjunto de restrições.


No contexto do exemplo, pode-se escrever as seguintes restrições (utilizando a linguagem CAMILA):

rei(r) = 
  { if(nome_(r) notin PessFamDB 
      → nome_(r) ++ "Não existe..."),
    if(datan_(r) > datam_(r) 
      → nome_(r) ++ "Morreu antes de nascer."),
    if(datam_(r) - datan(r) > 120 
      → nome_(r) ++ "Viveu demais!"),
    if(!all( x←decreto_l(r) : 
             datan_(r) < data_(x) /\ 
             data_(x) < datam_(r)) 
      → nome_(r) ++ "fez um decreto fora da sua vida!")
  };

Se o modelo instanciado tivesse os seguintes valores:

Este conjunto de valores faria disparar a regra

if(datan_(r) > datam_(r)
que produziria como resultado a concatenação ("++") do nome do rei ("nome_(r)") com a string "Morreu antes de nascer.".