Escrevendo um DTD: Como alcançar essa configuração de crianças
Pergunta
O elemento tasklist
pode conter no máximo um title
E no máximo um description
, além de qualquer número (incl. 0) task
elementos em qualquer ordem.
A abordagem ingênua não é aplicável, pois a ordem não deve importar:
<!ELEMENT tasklist (title?, description?, task*) >
Como alternativa, eu poderia nomear explicitamente tudo Opções possíveis:
(title, description?, task*) |
(title, task+, description?, task*) |
(task+, title, task*, description?, task*) |
(description, title?, task*) |
(description, task+, title?, task*) |
(task+, description, task*, title?, task*) |
(task*)
Mas então é muito fácil escrever uma regra não determinística e, além disso, parece o caminho direto para a loucura mais sombria. Alguma idéia, como isso poderia ser feito com mais elegância?
E não, um XSD ou relaxamento não é opção. Eu preciso de um DTD simples e antigo.
Solução
Isso resume o que você precisa:
<!ELEMENT tasklist (task*, ((title?, task*, description?) |
(description?, task*, title?)), task*)>
Alternância para o title
aparecendo antes/depois description
.
No entanto, este não é um modelo de conteúdo determinístico, como @13ren explica em sua resposta. [Aqui está outro exemplo da Microsoft] (http://msdn.microsoft.com/en-us/library/9bf3997x(vs.71).aspx).
Resumidamente
Seus requisitos são ter um modelo não determinístico e, como tal, não há não válido DTD para o seu cenário.
Alternativas
Se você colocar uma restrição simples que também task
ou description
deve ser o último elemento se ambos task
e description
são fornecidos, você pode usar esta declaração determinística do DTD:
<!ELEMENT tasklist (
task*,
((title, task*, description?) |
(description, task*, title?))?
)>
Exemplos:
<!-- Valid -->
<tasklist>
<task></task>
<task></task>
<task></task>
<title></title>
<task></task>
<description></description>
</tasklist>
<!-- Valid -->
<tasklist>
<title></title>
<task></task>
<task></task>
<task></task>
</tasklist>
<!-- Invalid
<tasklist>
<task></task>
<title></title>
<task></task>
<description></description>
<task></task>
</tasklist>
-->
Ou, possivelmente mais naturalmente, aplique que um title
ou description
elemento deve ser o primeiro elemento, e ambos title
e description
Os elementos devem existir ou não existentes.
<!ELEMENT tasklist (
((title, task*, description) |
(description, task*, title))?,
task*
)>
Exemplos:
<!-- Valid -->
<tasklist>
<title></title>
<task></task>
<description></description>
<task></task>
<task></task>
</tasklist>
<!-- Invalid
<tasklist>
<task></task>
<title></title>
<description></description>
<task></task>
<task></task>
</tasklist>
<tasklist>
<title></title>
<task></task>
<task></task>
<task></task>
</tasklist>
-->
Por outro lado
Caso contrário, você precisa usar o relaxamento NG, o que permite modelos não determinísticos.
Outras dicas
Por que a ordem não é importante?
Parece -me que a ordem é um pouco importante aqui; e que o único sensível O pedido é o título?, descrição?, tarefa*.
A flexibilidade é boa e tudo, mas às vezes não é necessária.