Search code examples
xmlrelaxng-compact

In Relax NG compact, how can I define 2 elements that at least one of is required?


I need to write an xml schema (i'm using relax NG to generate an rng...) that requires at least 1 of 2 different elements. So, if the elements are 'fruit' and 'vegetable', acceptable XML would contain 'fruit', 'vegetable', or both.

<fruit>apple</fruit>
<vegetable>broccoli</vegetable>

This is what I have so far, but this is fruit or vegetable, and if you pass neither fruit NOR vegetable, it works also...

& (element Fruit {
    xsd:string { .. }
| (element Vegatable {
    xsd:string { .. }
})? 

Update The answer seems correct, but I can't figure out how to integrate this. When you say I can't use an interleave, do you mean I can do something like this?

<meal>
  <drink>Water</drink>
  <meat>Chicken</meat>
  <fruit>Apple</fruit>
  <vegetable>Broccoli</vegetable>
</meal>

Where either fruit or vegetable or both is required?

Update 2: Does this look correct?

fruit = element fruit { xsd:string }
vegetable = element vegetable { xsd:string }
    
start =
  element Meal {
    element Drink { xsd:string },
    element Meat { xsd:string },
    ((fruit , vegetable?) | (fruit? , vegetable))
  }

Solution

  • The following Relax NG schema requires at least one fruit or one vegetable and allows both:

    start = element foo { (fruit, vegetable?) | (vegetable, fruit?) }
    fruit = element fruit { xsd:string }
    vegetable = element vegetable { xsd:string }
    

    I do not believe you could use the interleave pattern to meet your specification precisely.

    I've assumed you want a maximum of one fruit and one vegetable otherwise start could be this start = element foo { (fruit | vegetable)+ }.