XSD 使用通用限制模式验证所有元素的模式:例如允许的字符
XSD schema to validate all elements using a common restriction pattern: e.g. allowable characters
我有许多复杂的 XSD 文件用于验证传入的 XML。这些 XSD 是标准,会不时更新。
最重要的是,有一项业务限制规定在任何 element/attribute.
中只允许使用特定的拉丁字符、数字和符号子集
我的想法是创建一个通用的 XSD,而不是去每个 XSD 并为每个 simpleType 添加模式限制(由于多种原因这是不可能的)在应用特定 XSD 验证之前用作一般验证。
但是,我找不到对可变元素集应用相同限制的方法,无论它们声明在何处以及声明的深度如何。
为了给你一个想法,我想到了使用 xsd:any
并像这样应用相同的 simpleType
:
<!-- XSD for allowable characters -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="AppHdr" type="AnyRoot"/>
<xs:simpleType name="AnyElement">
<xs:restriction base="xs:string">
<xs:pattern value="[A-Za-z0-9]*"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="AnyRoot">
<xs:sequence>
<xs:any namespace="##any" processContents="skip"
minOccurs="0" maxOccurs="unbounded"
type="AnyElement"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
不幸的是,xs:any
中不允许有 type
属性,因此这是无效的。也许这与 xs:group
的组合可以解决问题?
搜索了任何替代方案但没有成功,我发现所有类似的方法都涉及更改原始 XSD 中具有已知名称和位置的特定元素。这对我来说不行。
起初,在我看来这似乎是微不足道且常见的情况,但事实证明这是一种罕见的情况。
如果有人能阐明它,我将不胜感激。谢谢!
[编辑]:
我最终决定走另一条路而不是 XSD,我正在使用 XSL 过滤无效字符,如果找到则返回报告。
<?xml version="1.0" encoding="UTF-8"?>
<!-- XSL for allowable characters: Andreas Gounaris, 2021 -->
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:devdom="http://example.com/xfunctions/"
extension-element-prefixes="devdom">
<xsl:output method="text" media-type="text/plain" indent="no" omit-xml-declaration="yes" encoding="UTF-8"/>
<!-- Matching document root -->
<xsl:template match="/">
<xsl:apply-templates select="*" mode="verify"/>
</xsl:template>
<!-- Remove whitespace between nodes -->
<xsl:template match="text()[not(normalize-space())]" mode="verify"/>
<xsl:template match="*" mode="verify">
<xsl:apply-templates select="@* | node()" mode="verify"/>
</xsl:template>
<!-- Matching attribute and text nodes -->
<xsl:template match="@* | text()" mode="verify">
<xsl:variable name="invalidContent" select="devdom:exslt_verify_mx_disclosure_chars(.)"/>
<xsl:if test="$invalidContent">
<xsl:value-of select="concat(name(parent::*), ': ', $invalidContent)"/>
<xsl:value-of select="'|-|'"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
转换器遍历所有属性和文本节点,并以当前节点作为参数调用 XSLT 外部函数 exslt_verify_mx_disclosure_chars
。
该函数匹配正则表达式中除有效字符外的任何字符。
在这个例子中,我返回一个字符串分隔的文本文件“|-|”但也可能是 XML。
使用 XPath 或 XSLT 2 或 3 的 Schematron 可能类似于
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
<pattern>
<rule context="text()[normalize-space()] | @*">
<assert test="matches(., '^[A-Za-z0-9]*$')">Only ASCII characters and digits</assert>
</rule>
</pattern>
</schema>
如果这是混合内容,那么您绝对不能这样做(没有 XSD 1.1 断言)- 无法限制混合内容中出现的文本。
对于简单类型,您可以使所有(基于字符串的)简单类型派生自具有适当模式限制的 xs:string 的子类型,但如果您觉得重构太多,那么您我们将不得不另辟蹊径。
如果您打算独立于 XSD 验证进行单独的验证通过,那么 XSD 似乎不是执行此操作的正确技术。如果您在 Java 世界中,我很想使用位于 XML 解析器和模式验证器之间的 SAX 过滤器来做到这一点。
我有许多复杂的 XSD 文件用于验证传入的 XML。这些 XSD 是标准,会不时更新。
最重要的是,有一项业务限制规定在任何 element/attribute.
中只允许使用特定的拉丁字符、数字和符号子集我的想法是创建一个通用的 XSD,而不是去每个 XSD 并为每个 simpleType 添加模式限制(由于多种原因这是不可能的)在应用特定 XSD 验证之前用作一般验证。
但是,我找不到对可变元素集应用相同限制的方法,无论它们声明在何处以及声明的深度如何。
为了给你一个想法,我想到了使用 xsd:any
并像这样应用相同的 simpleType
:
<!-- XSD for allowable characters -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="AppHdr" type="AnyRoot"/>
<xs:simpleType name="AnyElement">
<xs:restriction base="xs:string">
<xs:pattern value="[A-Za-z0-9]*"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="AnyRoot">
<xs:sequence>
<xs:any namespace="##any" processContents="skip"
minOccurs="0" maxOccurs="unbounded"
type="AnyElement"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
不幸的是,xs:any
中不允许有 type
属性,因此这是无效的。也许这与 xs:group
的组合可以解决问题?
搜索了任何替代方案但没有成功,我发现所有类似的方法都涉及更改原始 XSD 中具有已知名称和位置的特定元素。这对我来说不行。
起初,在我看来这似乎是微不足道且常见的情况,但事实证明这是一种罕见的情况。
如果有人能阐明它,我将不胜感激。谢谢!
[编辑]:
我最终决定走另一条路而不是 XSD,我正在使用 XSL 过滤无效字符,如果找到则返回报告。
<?xml version="1.0" encoding="UTF-8"?>
<!-- XSL for allowable characters: Andreas Gounaris, 2021 -->
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:devdom="http://example.com/xfunctions/"
extension-element-prefixes="devdom">
<xsl:output method="text" media-type="text/plain" indent="no" omit-xml-declaration="yes" encoding="UTF-8"/>
<!-- Matching document root -->
<xsl:template match="/">
<xsl:apply-templates select="*" mode="verify"/>
</xsl:template>
<!-- Remove whitespace between nodes -->
<xsl:template match="text()[not(normalize-space())]" mode="verify"/>
<xsl:template match="*" mode="verify">
<xsl:apply-templates select="@* | node()" mode="verify"/>
</xsl:template>
<!-- Matching attribute and text nodes -->
<xsl:template match="@* | text()" mode="verify">
<xsl:variable name="invalidContent" select="devdom:exslt_verify_mx_disclosure_chars(.)"/>
<xsl:if test="$invalidContent">
<xsl:value-of select="concat(name(parent::*), ': ', $invalidContent)"/>
<xsl:value-of select="'|-|'"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
转换器遍历所有属性和文本节点,并以当前节点作为参数调用 XSLT 外部函数 exslt_verify_mx_disclosure_chars
。
该函数匹配正则表达式中除有效字符外的任何字符。
在这个例子中,我返回一个字符串分隔的文本文件“|-|”但也可能是 XML。
使用 XPath 或 XSLT 2 或 3 的 Schematron 可能类似于
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
<pattern>
<rule context="text()[normalize-space()] | @*">
<assert test="matches(., '^[A-Za-z0-9]*$')">Only ASCII characters and digits</assert>
</rule>
</pattern>
</schema>
如果这是混合内容,那么您绝对不能这样做(没有 XSD 1.1 断言)- 无法限制混合内容中出现的文本。
对于简单类型,您可以使所有(基于字符串的)简单类型派生自具有适当模式限制的 xs:string 的子类型,但如果您觉得重构太多,那么您我们将不得不另辟蹊径。
如果您打算独立于 XSD 验证进行单独的验证通过,那么 XSD 似乎不是执行此操作的正确技术。如果您在 Java 世界中,我很想使用位于 XML 解析器和模式验证器之间的 SAX 过滤器来做到这一点。