1

从我到目前为止所看到的,我的问题可能无法在给定的限制内解决,但我会在这里给它一个机会。

我正在尝试编写一个与非常简单的 XML 匹配的 XSD(1.1) 文件。问题是 XML 标记中存在属性,这迫使我使用 xs:extension。一个元素的例子:

<xs:element name="Index">
    <xs:complexType>
        <xs:simpleContent>
            <xs:extension base="int1TO10">
                <xs:attribute name="comment" fixed="Attribute in XML Tag"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>
</xs:element>

而我创建的名为“int1TO10”的类型如下所示:

<xs:simpleType name="int1TO10">
    <xs:restriction base="xs:integer">
        <xs:minInclusive value="1"/>
        <xs:maxInclusive value="10"/>
    </xs:restriction>
</xs:simpleType>

这确实有效,问题在于它需要大量编写,如果您想更改某些内容,则需要更改引用名称以保持一致以及定义类型中的值。如果这是一个小文件,这将是可行的;但是这里有很多元素,它们几乎可以有最小和最大整数的任意组合。因此,对于每个新元素,有人必须检查一个类型是否已经存在,或者必须创建它。这一切都让人感到难以置信的多余。

我正在寻找的是一个简单的解决方案:

<xs:element>...
    <xs:extension base="xs:integer" minInclusive="1" maxInclusive="10">
        <xs:attribute name="comment" fixed="Attribute in XML Tag"/>
    </xs:extension>...
</xs:element>    

尽管从我的发现来看,这似乎是不可能的。例如,在这个 Stackoverflow 帖子中,接受的答案表明我目前正在做的事情就是要走的路;虽然那个帖子已经有点老了,所以也许我错过了一些最近的突破?

我能想到的唯一其他选择是重组 XML 文件本身,从 (current)

<Index comment="Attribute in XML Tag">(some value between 1 and 10)</Index>

<Index>
    <value>(some value between 1 and 10)</value>
    <comment>Attribute now in its own tag</comment>
</Index>

这还需要相当多的工作和更改与 XML 一起使用的其他一些东西(脚本等),所以我宁愿避免这种情况。

所以总结一下:有没有办法不为我的元素可以拥有的每个新 Integer 组合编写新的 simpleType ?欢迎提出任何建议,也许还有完全不同的方法或 XSD 结构?

4

2 回答 2

1

基于域名的名称

第一个建议:使用对您的域有意义的名称,而不是基于允许范围的名称。例如,使用Score而不是int1TO10Degrees而不是int1TO360; LindenRathanNumber而不是int323TO9043.

除了遵循使用基于域的名称的最佳实践之外,这种方法还具有将范围视为实现细节的良好特性。如果将来 LindenRathan Number 最大值从 9043 更改为 9044,则可以在定义中更改一次,而不是名称本身出现的任何地方。

完全参数化的端点

替代建议:如果出于某种无法解释的原因,在您希望公开特定允许范围的地方创建标记很重要,您可以一路走下去,并为端点提供明确的 XML 属性:

<n min="0" max="10">9</n>

然后,使用 XSD 1.1 断言,您可以将元素值限制在给定端点的范围内:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
           vc:minVersion="1.1"> 

  <xs:element name="n" type="IntRangeType"/>

  <xs:complexType name="IntRangeType">
    <xs:simpleContent>
      <xs:extension base="xs:int">
        <xs:attribute name="min" type="xs:int"/>
        <xs:attribute name="max" type="xs:int"/>
        <xs:assert test="@max >= @min"/>
        <xs:assert test=". >= @min and . &lt;= @max"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:schema>
于 2015-07-07T12:51:53.123 回答
0

我认为你所提出的就是要走的路。

然而,你可能...

  • 为您的范围类型使用一致的命名方案int_<lower_bound>_to_<upper_bound>,并使用独立于 xml 模式的文本处理工具从模板自动生成匹配的 xsd 类型声明。

  • 转换你想出的语法(<xs:extension base="xs:integer" minInclusive="1" maxInclusive="10">使用 xslt.

概念验证

生成(perl)

写入一个包含 xml 片段的文件,该片段由系统生成的类型定义组成。

use IO::File;
use warnings;
use strict;

my ($dict, $fh_out, $fpath, $instance);
my $tmpl =<<EOTMPL;
<xs:simpleType name="int\${lb}TO\${ub}">
    <xs:restriction base="xs:integer">
        <xs:minInclusive value="\${lb}"/>
        <xs:maxInclusive value="\${ub}"/>
    </xs:restriction>
</xs:simpleType>
EOTMPL

my %dict = ( 'lb' => 0,  'ub' => 0 );
$fpath = "<wherever>";
$fh_out = new IO::File ( ">" . $fpath );

for ($dict{lb} = 1; $dict{lb} <= 4; $dict{lb}++ ) {
    for ($dict{ub} = $dict{lb}+1; $dict{ub} <= 4; $dict{ub}++ ) {
        ($instance = $tmpl) =~ s/\$\{([a-z]+)\}/$dict{$1}/g;
        print $fh_out "$instance\n";
    }
}

$fh_out->close;

exit(0);

变换 (xslt)

将源文件中的所有伪类型规范转换为成熟的int<m>TO<n>类型声明。不检查重复定义。

<?xml-stylesheet version="2.0" encoding="utf-8"?>
<!--
    t.xslt
    XSD typespec generation
-->
<xsl:stylesheet xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <!--
        Specifying the output
    -->
    <xsl:output method="xml" encoding="utf-8" indent="yes"/>

    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:template>

    <!--
           Toplevel template:
    -->
    <xsl:template match="/">
        <xsl:message select="string('main template: start;')"/>
        <mytypes xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <xsl:apply-templates />
        </mytypes>
        <xsl:message select="string('main template: end;')"/>
    </xsl:template>

    <!--
           Type subst
    -->
    <xsl:template match="xs:element/xs:complexType/xs:simpleContent/xs:extension[@base='xs:integer'][@minInclusive][@maxInclusive]">
        <xs:simpleType>
            <xsl:attribute name='name' select="concat('int', string(@minInclusive), 'TO', string(@maxInclusive))"/>
            <xs:restriction base="xs:integer">
                <xs:minInclusive><xsl:attribute name='value' select="number(@minInclusive)"/></xs:minInclusive>
                <xs:maxInclusive><xsl:attribute name='value' select="number(@maxInclusive)"/></xs:maxInclusive>
            </xs:restriction>
        </xs:simpleType>
    </xsl:template>
</xsl:stylesheet>
于 2015-07-07T09:48:33.547 回答