C.3. Regras para os atributos

Cada um dos atributos no DTD vai corresponder a um símbolo não-terminal na gramática de atributos.

O SGML permite definir atributos de vários tipos. Apresenta-se, primeiro, uma regra geral que deverá ser aplicada sempre, independentemente do tipo do atributo. A seguir, apresentam-se as regras que permitem converter os tipos mais usuais de atributos.

C.3.1. Elemento com atributos

Se elem tem atributos, sejam eles att1, ..., attn.

A sua declaração no DTD seria:

          <!ATTLIST elem att1 att1-type att1-def-value
                        ...
                        attn attn-type attn-def-value>

A produção principal correspondente à regra geral, é:

          elemAttList → Att1 ... Attn
onde Atti é o símbolo não-terminal introduzido para representar o atributo atti.

att1-type, ..., attn-type representam o tipo de cada um dos atributos: enumerado, CDATA, NUMERICAL, ID, IDREF, IDREFS, ENTITY, e outros que já não se utilizam. Na declaração de um atributo também podemos associar-lhe um valor por omissão, representado acima por atti-def-value, que deve ser tido em conta sempre que o atributo não for instanciado pelo utilizador. Os valores possíveis para este são os definidos na tabela abaixo: #FIXED seguido de uma string, o que significa que se o atributo for instanciado terá que ser com um valor igual a string; um dos valores pertencentes a um tipo enumerado definido para esse atributo; ou uma das palavras-chave seguintes:

Tabela C-1. Valores por omissão de Atributos

#IMPLIEDo valor poderá não ser instanciado, o atributo é opcional.
#REQUIREDo utilizador terá obrigatoriamente que instanciar o atributo, este é obrigatório
#FIXEDo valor do atributo tem que aparecer a seguir à palavra-chave (ver Secção 7.1, Exemplo 7-3) significando que se o atributo for instanciado terá que ser com um valor igual ao declarado, caso não seja instanciado o sistema assumirá esse valor.
#CURRENTo valor do atributo é herdado da última instância do mesmo elemento onde o valor do atributo foi instanciado (segue-se a ordem ascendente na árvore de elementos)
#CONREFo valor é usado para referências externas (cada vez menos utilizado, não irá ser considerado nas regras que se seguem)
valor de um tipo enumeradoum dos valores pertencentes ao tipo enumerado definido para esse atributo.

O valor por omissão levanta um problema: não é possível derivá-lo da gramática, ou seja, o comportamento deste item é essencialmente semântico - "se o atributo não estiver instanciado, então use-se este valor". Como tal, recorre-se a equações sobre atributos (da gramática de atributos) para o modelar, como se poderá ver nas regras seguintes.

As restantes produções de cada um dos atributos dependem dos seus tipos e valores por omissão. Serão tratadas nas regras que se seguem.


Exemplo C-4. Elemento News com atributos

No caso de estudo do serviço noticioso, o elemento News tinha dois atributos: Type e Subject. Assim, as produções correspondentes são:

          News → NewsAttList NewsContent
          NewsAttList → Type Subject


O conteúdo do elemento pode ser estruturado ou texto.

C.3.2. Atributo do tipo enumerado

Se um atributo att do elemento X for declarado da seguinte maneira:

<!ATTLIST X att (att-val1 | ... | att-valn) att-vali>

é do tipo enumerado: o seu tipo está definido como a lista att-val1, ..., att-valn, e o seu valor por omissão é att-vali com 0<i<n. As produções correspondentes são:

          att → att-val1
              | ...
              | att-valn
              | &egr;

Os símbolos att-val1, ..., att-valn são símbolos terminais da gramática, correspondem a tokens/palavras-chave fixos; &egr; corresponde à string vazia e esta derivação corresponde à inexistência do atributo na instância documental (a situação em que o utilizador não instancia o atributo) e onde deverá ser assumido o valor por omissão.

Assim as produções anteriores têm de ser enriquecidas com as seguintes equações sobre o atributo gramatical valor, que irá guardar o valor do atributo SGML att:

          att → att-val1
                  valor = f(att-val1)
              | ...
                  ...
              | att-valn
                  valor = f(att-valn)
              | &egr;
                  valor = f(att-vali)

Aqui e no resto das regras, a função f representa a conversão de tipos necessária para passar o valor devolvido pelo analisador léxico (tipo=string) para o valor pretendido no atributo semântico.


Exemplo C-5. Atributo do tipo enumerado

No sistema noticioso, o elemento News tem um atributo de nome Type do tipo enumerado, com valores Event ou Novelty, o que dá origem às seguintes produções:

          Type → event
                   valor = "Event"
               | novelty
                   valor = "Novelty"


C.3.3. Atributo do tipo CDATA

Se um atributo for do tipo CDATA, significa que tem um conteúdo textual e a produção correspondente é:

          att → str
                  valor = f(str)

O símbolo str é um símbolo terminal da gramática resultante.

C.3.4. Atributo do tipo NUMERICAL

Se um atributo for do tipo NUMERICAL, significa que tem um conteúdo numérico e a produção correspondente é:

          att → number
                  valor = f(number)

O símbolo number é um símbolo terminal da gramática resultante.

C.3.5. Atributo do tipo ID

Se um atributo for do tipo ID, significa que tem um conteúdo textual e uma semântica associada: o valor do atributo, instanciado pelo utilizador, tem que ser único, i.e., não pode haver no documento mais nenhum atributo deste tipo instanciado com o mesmo valor. A produção e semântica correspondentes são:

          att → ident
                 if( exists(ident, Tabid) )
                   erro = "Identificador já existente!"
                 else insert(ident, Tabid)
                 valor = f(ident)

C.3.6. Atributo do tipo IDREF

Se um atributo for do tipo IDREF, significa que tem um conteúdo textual e uma semântica associada, que é o inverso da situação anterior: o valor do atributo, instanciado pelo utilizador, tem que existir na tabela de identificadores, tem que estar declarado num atributo do tipo ID algures no documento. A produção e a semântica correspondentes definem-se como:

          att → ident
                  if( !exists(ident, Tabid) )
                    erro = "Identificador inexistente!"      
                  valor = f(ident) 

C.3.7. Atributo do tipo ENTITY

Se um atributo for do tipo ENTITY, significa que tem um conteúdo textual e uma semântica associada: o valor do atributo, instanciado pelo utilizador, tem que ser o identificador de uma entidade existente na tabela de entidades, tem que estar declarado numa declaração de entidade no DTD (Secção C.4). A produção e a semântica correspondentes definem-se como:

          att → ent-ident
                  if( !exists(ent-ident, Tab-entidade) )
                    erro = "Entidade inexistente!"
                  valor = f(ent-ident)

C.3.8. Atributo definido com o valor #IMPLIED

Se um atributo for definido com o valor por omissão #IMPLIED, significa que é opcional e as produções correspondentes são:

          att → att-val
              | &egr;

A derivação pela string vazia acresce a uma das conversões anteriores dependendo do tipo. A produção att → att-val representa a produção resultante da conversão do tipo de atributo; ao juntar-se a conversão do valor por omissão acrescentam-se produções à derivação de att e, nalguns casos, alguns atributos e respectivas equações de cálculo.

C.3.9. Atributo definido com o valor #REQUIRED

Se um atributo for definido com o valor por omissão #REQUIRED, significa que é obrigatório e as produções correspondentes são:

          att → att-val
              | &egr;
                  erro = "Atributo obrigatório!"  

A derivação pela string vazia acresce a uma das conversões anteriores dependendo do tipo.

C.3.10. Atributo definido com o valor #FIXED

Se um atributo for definido com o valor por omissão #FIXED, significa que o seu valor foi fixo na declaração. O utilizador poderá sempre instanciá-lo mas o valor terá que ser igual ao fornecido na declaração do atributo no DTD. As produções e a semântica correspondentes definem-se como:

          att → att-val
                  if(f(att-val) != Tab-attr(att).valor)
                    erro = "O valor do atributo não é o esperado!"
                  valor = Tab-attr(att).valor
                    
              | &egr;
                  valor = Tab-attr(att).valor  

A derivação pela string vazia e as condições de contexto acrescem a uma das conversões anteriores dependendo do tipo.

C.3.11. Atributo definido com o valor #CURRENT

Este valor por omissão só se utiliza para atributos pertencentes a elementos que podem aninhar-se. Por exemplo, um documento pode construir a sua hierarquia de secções e subsecções à custa de apenas um elemento secção ao qual, no DTD, se deu permissão para aninhar recursivamente. Assim, uma secção que ocorra dentro de outra secção é uma subsecção daquela ou uma secção de nível dois.

Este tipo de elementos tem, normalmente, atributos, que se forem declarados com o valor por omissão #CURRENT não precisam de estar instanciados, nesse caso, o atributo herdará o seu valor da última instanciação desse atributo percorrendo os elementos de baixo para cima até encontrar um que o tenha instanciado.

As produções e a semântica correspondentes definem-se como:

          att → att-val
                  valor = f(att-val)   
              | &egr;
                  valor = Procura(att, ASAD)  

A função Procura vai tentar calcular o valor do atributo percorrendo a árvore de sintaxe abstracta decorada calculada até ao momento, em ordem ascendente.

A derivação pela string vazia e as condições de contexto acrescem a uma das conversões anteriores dependendo do tipo.