Generating XSD from RelaxNG while keeping root-element restriction

389 views Asked by At

I want to convert the following schema from RNC/RNG to W3C XSD.

default namespace = ""
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
namespace rng = "http://relaxng.org/ns/structure/1.0"

start = starting_risk

starting_risk =
  element risk {
    element continents { Continents }?
  }

Continents = element continent { Continent }+
Continent =
  element country { Country }*,
  element sea { Sea }*
Country = xsd:string { minLength = "1" maxLength = "100" }
Sea = xsd:string { minLength = "1" maxLength = "100" }

Using trang, I end up with

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="risk">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" ref="continents"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="continents" type="Continents"/>
  <xs:complexType name="Continents">
    <xs:sequence>
      <xs:element maxOccurs="unbounded" ref="continent"/>
    </xs:sequence>
  </xs:complexType>
  <xs:element name="continent" type="Continent"/>
  <xs:complexType name="Continent">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" ref="country"/>
      <xs:element minOccurs="0" maxOccurs="unbounded" ref="sea"/>
    </xs:sequence>
  </xs:complexType>
  <xs:element name="country" type="Country"/>
  <xs:element name="sea" type="Sea"/>
  <xs:simpleType name="Country">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="100"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="Sea">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="100"/>
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

The problem is that the hierarchy is lost. The 'risk' element is the root of the schema and the only valid element at that level. In the RNC, the relationship between 'risk' and 'continent' elements is parent to child. But in the XSD, they are siblings. What am I doing wrong/ have I not understood?

1

There are 1 answers

2
sideshowbarker On BEST ANSWER

You’re not doing anything wrong. I think unfortunately you just can’t use trang to generate an XSD from your RNC schema that preserves the restriction on what’s allowed as the root element.

You could instead manually create an XSD restricted to having risk be the only global element, with all the rest of the elements each being a local element. But (as far as I know) you can’t generate such an XSD using trang. The reason is that (again, as far as I know at least) trang basically always generates XSDs only with global elements.

You might think you could generate an XSD with local elements if you wrote your RNC like this:

start =
element risk {
  element continents {
    element continent {
      element country { xsd:string { minLength = "1" maxLength = "100" } }*,
      element sea { xsd:string { minLength = "1" maxLength = "100" } }*
    }+
  }?
}

That’s basically structured in the same way you’d want to structure your XSD if you did it manually.

But if you run that through trang to generate an XSD, you’ll find that every single element comes out as a global element in the resulting XSD. That’s just how trang always does it.

So unless there’s some magic way I’m unaware of to force trang to do otherwise, your only alternative if you want to restrict your XSD schema to only having risk allowed as the root element is, create the XSD manually.

I guess that could be seen as a design flaw in trang, but arguably the real problem is that XML Schema by design has nothing similar to RelaxNG’s start to explicitly specify a root element.

If XML Schema did have a similar simple way like RelaxNG’s start to specify what’s allowed as the root element, then trang could just output that in the XSD and you’d have what you want.

But because XSD has nothing like start, your only mechanism for restricting your schema to having only one particular root element is to completely (re)structure your XSD into the “local style”.

However, as mentioned earlier in this answer, you unfortunately can’t generate such a “local style” XSD from RelaxNG sources using trang. You instead must separately create the XSD manually.

It’s imaginable trang ideally could have been designed with some option to allow you to generate “local style” XSDs or maybe with some heuristics to somehow infer when that’s the output style it should use. But the reality is, that’s not the way trang actually works, and it’s not going to change.

So while I’m sure that isn’t the answer you were hoping to get, I hope it helps clarify things.