从我看到的到现在为止,我的问题可能无法在给定的约束条件下解决,但我会在这里给它一个机会。
我正在尝试编写一个与非常简单的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>
而我创建的类型称为&#34; int1TO10&#34;看起来像这样:
<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>
虽然从我发现的情况来看,这似乎不可能。例如,在this Stackoverflow post中,接受的答案表明我目前正在采取的方式是要走的路;虽然这个帖子已经有点老了,所以也许最近有一些我错过的突破?
我能提出的另一个选择是从(当前)
重构XML文件本身<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结构可能吗?
答案 0 :(得分:1)
第一个建议:使用对您的域有意义的名称,而不是基于允许范围的名称。例如,使用Score
而不是int1TO10
; Degrees
而不是int1TO360
; LindenRathanNumber
而不是int323TO9043
。
除了遵循使用基于域名的最佳实践之外,此方法还具有将范围视为实现细节的良好属性。如果将来LindenRathan数字的最大值从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 . <= @max"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
答案 1 :(得分:0)
我认为你提出的是要走的路。
但是,你可以......
对范围类型使用类似int_<lower_bound>_to_<upper_bound>
的一致命名方案,并使用独立于xml架构的文本处理工具从模板自动生成匹配的xsd类型声明。
使用xslt转换您提出的语法(<xs:extension base="xs:integer" minInclusive="1" maxInclusive="10">
。
<强>的PoC 强>
生成(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>