Page 1 of 1

Need help with Relax NG Compact schema

Posted: Thu Jan 10, 2008 7:55 pm
by Zearin
I'm trying to write a Relax NG Compact schema. RNC syntax is an absolute dream compared to XSD, and I like it better than regular RNG, too. But I'm trying to do something that's a little tricky.

I'm trying to write a schema that defines the elements <courses> and <course>. Basically, I want to be able to specify optional attributes on <courses>, but if specified disallows the attributes on nested <course> elements.

For example, the following would be legal:

Code: Select all


<courses dept="ENGL">
<course number="101" />
<course number="201" />
</courses>
And the following would also be legal:

Code: Select all


<courses>
<course dept="ENGL" number="101" />
<course dept="ENGL" number="201" />
</courses>
But the following should be illegal:

Code: Select all


<courses dept="ENGL">
<course dept="ENGL" number="101" />
<course dept="ARTT" number="201" />
</courses>
…Because if <courses> has specified a @dept, no contained elements should be allowed to specify @dept of their own. (The idea is that they "inherit" their parent's @dept value.)

Does anyone know how to write this in Relax NG Compact syntax? (If not, does anyone have any advice?)[/code]

Posted: Fri Jan 11, 2008 5:28 pm
by Dan
Here it is the schema in Relax NG compact syntax that defines the <courses> element as a choice. I named the root element <test>:

Code: Select all


default namespace = ""
start =
element test {
element courses {
(
attribute dept { xsd:NCName },
element course {
attribute number { xsd:integer }
}+
) |
(
element course {
attribute dept { xsd:NCName },
attribute number { xsd:integer }
}+
)
}+
}
The XML I have used to test it was derived from your examples:

Code: Select all


<?oxygen RNGSchema="relaxNgTest.rnc" type="compact"?>
<test>
<!-- Valid -->
<courses dept="ENGL">
<course number="101"/>
<course number="201"/>
</courses>

<!-- Valid -->
<courses>
<course dept="ENGL" number="101"/>
<course dept="ENGL" number="201"/>
</courses>

<!-- Not Valid -->
<courses dept="ENGL">
<course dept="ENGL" number="101"/>
<course dept="ARTT" number="201"/>
</courses>
</test>
Best regards,
Dan

Is there another way?

Posted: Sat Jan 12, 2008 3:50 am
by Zearin
Thanks. :o

However, I was looking to utilize one of Relax NG Compact's abilities to redefine elements. Your example is a workable solution, but these two elements are just one pair among many that I want to write, and writing out the complete definition for each context would get pretty tiresome. :?

I know about the include directive and its ability to redefine elements, but what I'm fuzzy on is how to redefine an element in as efficient a manner as possible.

For example, let's say I have the following named patterns (capitalized for easy identification):

Code: Select all


Courses = element courses {
Course+
}
Course = element course { course.attlist }
course.attlist =
attribute dept {text}?,
attribute number {text},
attribute credits {xsd:nonNegativeInteger}?,
attribute grade {xsd:string{minLength="1" maxLength="2"}}?,
attribute title {text}?,
attribute description {text}?
Now, according to the Relax NG Compact tutorial, there's a way to say "everything but" by using a minus operator. Then there is also the notAllowed keyword.

But whenever I try to use either, the validator lights up with errors. (And as although I am very happy with Oxygen, the errors for RNG Compact files don't explain the problem at all. I know RNG Compact isn't XML, but it's designed to be 1-to-1 compatible with XML, which should theoretically allow the editor to provide more helpful tooltips…)

So continuing the example above, what I would like to do is something sort of like the following… (this is invalid, but I'm just trying to communicate what I'm trying accomplish)

Code: Select all


Courses = element courses {
(
attribute dept {text},
Course {attribute dept = notAllowed}+
) |
Course+
}
Course = element course { course.attlist }
course.attlist =
attribute dept {text}?,
attribute number {text},
attribute credits {xsd:nonNegativeInteger}?,
attribute grade {xsd:string{minLength="1" maxLength="2"}}?,
attribute title {text}?,
attribute description {text}?

Second example…

Posted: Sat Jan 12, 2008 4:07 am
by Zearin
I thought of another way to write my last codeblock that might make slightly more sense (though still invalid :( ):

Code: Select all


Courses = element courses {
(
attribute dept {text},
Course = element course {course.attlist - attribute dept}
) |
Course+
}
Course = element course { course.attlist }
course.attlist =
attribute dept {text}?,
attribute number {text},
attribute credits {xsd:nonNegativeInteger}?,
attribute grade {xsd:string{minLength="1" maxLength="2"}}?,
attribute title {text}?,
attribute description {text}?

Posted: Wed Jan 16, 2008 4:42 pm
by Dan
Unfortunately, you cannot use the minus operator. It is intended only for use with name classes, not with patterns. I spent some time trying to find a correct way of rewritting a pattern similar to the one you suggested, but the results were more complicated that the basic solution of using a choice.

(Another solution for such a problem would be Relax NG in XML syntax and embedded Schematron rules, but I am not sure if it is acceptable for you..)

Thank you. :)

Posted: Wed Jan 16, 2008 6:47 pm
by Zearin
Thank you. :)

Damn. I was afraid that was the case.

Relax NG XML syntax isn't bad, and isn't off-limits for any technical reason. I'm just using RNG Compact for easy of writing & reading. I love what XML can do, but all those pointy angular brackets sure do get to be a burden on the eyes, sometimes… :wink:

Just out of curiosity, do you (or anybody else?) know why one can't use the minus operator with patterns?

My gut feeling is that if you can name a pattern, and if you can use an operator on a named pattern, you should be able to use an operator on any pattern. (But I'm not clever enough to invent syntaxes, so I can't figure that one out on my own.)