限制XSD中嵌套元素的深度

4

使用XML模式,能否限制父元素中嵌套的子元素的深度?

这里的背景是我从管理系统收集警报,并希望提供一个XML文档,允许最终用户定义一些规则,以便将警报过滤到UI中的文件夹中。我想将嵌套文件夹的深度限制为3,这样最终用户就不能嵌套数百层 - 因为过多的层次过滤最终会导致应用程序崩溃。

我可以编写一些代码来处理此问题,但如果可能的话,在模式中定义这些内容似乎更合适。

例如,以下内容是可以接受的:

<group name="Folder 1">
        <group name="Folder 2">
            <group name="Folder 3">
                <group name="Folder 4">
                </group>
            </group>
        </group>
    </group>

如果文件夹5太深,则此操作将无效。

<group name="Folder 1">
        <group name="Folder 2">
            <group name="Folder 3">
                <group name="Folder 4">
                    <group name="Folder 5">
                    </group>
                </group>
            </group>
        </group>
    </group>

我的模式看起来像这样,但它不能限制上面片段的深度。

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="hierarchy">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="group" type="GroupType" />
      </xs:sequence>
      <xs:attribute name="name" type="xs:string" />
    </xs:complexType>
  </xs:element>

  <xs:complexType name="GroupType">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="group" type="GroupType" />
    </xs:sequence>
    <xs:attribute name="name" type="xs:string" use="required" />
    <xs:attribute name="filterOn" type="xs:string" use="optional" />
    <xs:attribute name="operator" type="xs:string" use="optional" />
    <xs:attribute name="value" type="xs:string" use="optional" />
  </xs:complexType>
</xs:schema>

非常感谢您的指导!
1个回答

4
在XML Schema中,没有简单易用的解决方案(但其他语言中有),但你实际上可以通过自己嵌套整个内容来实现,但我不建议这样做。因此,如果我是你,我会采取以下两种方法之一:
1. 选择XML Schema的替代方案(或扩展)。参见:http://en.wikipedia.org/wiki/XML_schema#XML_schema_languages(查看RELAX和Schematron)。
2. 在应用程序中进行深度检查,如果depth > 3,则拒绝该内容,并在XML Schema和应用程序的文档中清楚地说明行为。
引用来自XML Schema版本1.1(候选推荐)的Wiki:
“通过XPath 2.0表达式(从Schematron借鉴的想法)定义针对文档内容的断言的能力。” <- 这将使深度定义变得非常容易。
关于如何在XMLSchema中表示嵌套深度的评论:
基本上,你可以像下面这样做(仍然建议在代码中执行)。然后添加属性,调整深度等(你可能可以使用extensionrestrict重复使用属性,但我不确定)。如果允许多种子元素,则此方法可能会变得非常恶劣(指数级)。
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://somenamespace.com"
           xmlns="http://somenamespace.com">

  <xs:element name="hierarchy">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="group" type="GroupTypeDepth0" />
      </xs:sequence>
      <xs:attribute name="name" type="xs:string" />
    </xs:complexType>
  </xs:element>

  <xs:complexType name="GroupTypeDepth0">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="group" type="GroupTypeDepth1" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="GroupTypeDepth1">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="group" type="GroupTypeDepth2" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="GroupTypeDepth2"/>
</xs:schema>

有效:

<hierarchy xmlns="http://somenamespace.com">
  <group>
    <group>
      <group/>
    </group>
  </group>
</hierarchy>

无效的:

<hierarchy xmlns="http://somenamespace.com">
  <group>
    <group>
      <group>
        <group/>
      </group>
    </group>
  </group>
</hierarchy>

我该如何嵌套模式以实现此目的?不幸的是,由于许可证问题,我无法添加支持RELAX / Schematron所需的第三方库(Java应用程序),因此必须使用XML模式。即使方案解决方法很混乱,我可能最终不得不编写一些非常不优雅的代码来支持它,但这可能是两害相权取其轻的选择。 - tja

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接