在保持根元素限制的同时从 RelaxNG 生成 XSD

Generating XSD from RelaxNG while keeping root-element restriction

我想将以下架构从 RNC/RNG 转换为 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" }

使用 trang,我得到

<?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>

问题是层次结构丢失了。 'risk' 元素是架构的根,也是该级别上唯一有效的元素。在 RNC 中,'risk' 和 'continent' 元素之间的关系是父子关系。但在XSD,他们是兄妹。我做错了什么/我没听懂吗?

你没有做错任何事。我认为不幸的是,您不能使用 trang 从您的 RNC 架构中生成一个 XSD,该架构保留对允许作为根元素的限制。

您可以改为手动创建一个 XSD,限制为 risk 是唯一的 global element, with all the rest of the elements each being a local element。但是(据我所知)你不能使用 trang 生成这样的 XSD。原因是(同样,至少据我所知)trang 基本上总是仅使用全局元素生成 XSDs。

您可能会认为,如果您像这样编写 RNC,就可以生成具有本地元素的 XSD:

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

这基本上与您手动构建 XSD 的方式相同。

但是如果你 运行 通过 trang 生成一个 XSD,你会发现每个单独的元素在结果 [=55= 中作为全局元素出现]. trang 就是这样做的。

所以除非有一些我不知道的神奇方法强制 trang 否则,如果你想将你的 XSD 模式限制为只有 risk,你唯一的选择允许作为根元素,手动创建 XSD。

我想这可能被视为 trang 中的设计缺陷,但可以说真正的问题是 XML 设计模式与 RelaxNG 的 start 没有任何相似之处来明确指定根元素。

如果 XML Schema 确实有类似 RelaxNG 的 start 的简单方法来指定允许的根元素,那么 trang 可以只在 XSD 你会得到你想要的。

但是因为 XSD 与 start 完全不同,所以将架构限制为只有一个特定根元素的唯一机制是将 XSD 完全(重新)构造为“local style”.

但是,如本回答前面所述,不幸的是,您无法使用 trang 从 RelaxNG 源中生成这样的“本地样式”XSD。您必须手动单独创建 XSD。

这是可以想象的 trang 理想情况下可以设计一些选项以允许您生成“本地样式” XSD 或者可能使用一些启发式方法以某种方式推断何时是它应该的输出样式采用。但事实是,trang 并不是这样运作的,而且不会改变。

所以虽然我确定这不是您希望得到的答案,但我希望它有助于澄清问题。