DTD required elements ordering
Asked Answered
J

4

13

I want to have list of required elements in any order defined in dtd, but have no idea how I could do this.

For example, I have following definition:

<!ELEMENT parent (child1, child2, child3)>

This dtd declaration will successfully validate following piece of xml:

<parent>
   <child1></child1>
   <child2></child2>
   <child3></child3>
</parent>

But in following case xml will not pass validation:

<parent>
   <child2></child2>
   <child1></child1>
   <child3></child3>
</parent>

One of the possible solution is to declare

<!ELEMENT parent (child1 | child2 | child3)>

But in this case one of the childs might be missing though validation will be successful.

I need correct dtd element declaration for the case when list of required elements can be present in any order.

Jardiniere answered 11/6, 2010 at 12:52 Comment(1)
I just about posted this question a few minutes ago. Totally lame that you can't re-order these.Nipa
V
12

ChrisF is wrong to say you can't do this (but kudos for checking the spec!); DevNull [now known as Daniel Haley] is right to say you can.

There is, however, one complication: the content model given by DevNull for parent violates the determinism rules of XML. Informally, these rules say the parser must know, without lookahead, which token in the content model each element in the document matches. If in a parent element the parser sees a child1, it can't know without lookahead whether it has just matched the first or second occurrence of child1 in DevNull's content model. This is an error (but as it happens it's an error that processors are not obligated to report -- it's an error that means "all bets are off, the processor may do anything here, including fail to notice anything is wrong").

A content model for parent that obeys the determinism rules can be formed by factoring out common prefixes, thus:

<!ELEMENT parent ( 
                   (child1, ( (child2,child3)
                            | (child3,child2)))
                 | (child2, ( (child1,child3)
                            | (child3,child1)))
                 | (child3, ( (child1,child2)
                            | (child2,child1)))
                 ) >

This is less convenient than declarations for this model can be in other schema languages, and for more than three elements it's error prone and extremely tedious to do by hand. But it's not impossible to declare the content model you want with DTDs. Or perhaps I should say it's impossible only for DTD authors who are incapable of putting up with any inconvenience.

Note also that unless the sequence of children carries some information, some design authorities argue strongly that it's better to fix a sequence.

Virginia answered 25/9, 2012 at 0:3 Comment(0)
G
9

Try:

<!ELEMENT parent (child1 | child2 | child3)*>

Should allow zero or more of any child, in any order.

Grimbal answered 16/10, 2011 at 19:6 Comment(2)
I don't think this would work because it sounds like the OP needed all 3 child elements present. This is based on the OP's statement: "But in this case one of the childs might be missing though validation will be successful."Gans
Beautiful answer. It's great for dealing with unordered elements of which you know what they will be, but not their order or quantity. Thank you @Grimbal !Maraud
A
2

Reading the spec is would appear you can't.

When children are declared in a sequence separated by commas, the children must appear in the same sequence in the document. In a full declaration, the children must also be declared, and the children can also have children.

I think it's because you are declaring a sequence (or ordered list if you like) rather than a collection (or unordered list).

Also answered 11/6, 2010 at 13:30 Comment(0)
G
2

This is tricky when you need exactly one of each child elements. This is the only way I can think of and it's not very pretty. It works though...

<!ELEMENT parent ( 
                 (child1,child2,child3)|
                 (child1,child3,child2)|
                 (child2,child1,child3)|
                 (child2,child3,child1)|
                 (child3,child1,child2)|
                 (child3,child2,child1)
                )>

Basically I'm specifying every possible combination of exactly one child1, child2, and child3 elements.

Here's an example instance. child1, child2, and child3 can be in any order, but they each must occur exactly one time.

<!DOCTYPE parent [
<!ELEMENT parent ( 
                 (child1,child2,child3)|
                 (child1,child3,child2)|
                 (child2,child1,child3)|
                 (child2,child3,child1)|
                 (child3,child1,child2)|
                 (child3,child2,child1)
                )>
<!ELEMENT child1 (#PCDATA)>
<!ELEMENT child2 (#PCDATA)>
<!ELEMENT child3 (#PCDATA)>
]>
<parent>
  <child2></child2>
  <child1></child1>
  <child3></child3>
</parent>
Gans answered 17/10, 2011 at 16:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.