【问题标题】:XSD schema to validate all elements using a common restriction pattern: e.g. allowable charactersXSD 模式使用通用限制模式验证所有元素:例如允许的字符
【发布时间】:2021-09-13 11:42:17
【问题描述】:

我有许多用于验证传入 XML 的复杂 XSD 文件。这些 XSD 是标准,并且会不时更新。

除此之外,还有一项业务限制规定,任何元素/属性中只能允许使用特定的拉丁字符、数字和符号子集。

我的想法是创建一个通用 XSD,在特定 XSD 之前用作通用验证,而不是去每个 XSD 并为每个 simpleType 添加模式限制(由于多种原因这是不可能的)将应用验证。

但是,我找不到将相同限制应用于可变元素集的方法,无论它们声明的位置和深度。

为了给你一个想法,我想使用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。 该函数匹配正则表达式中任何但有效的字符。

在这个例子中,我返回一个 str 分隔的文本文件 '|-|'但它也可以是 XML。

【问题讨论】:

  • 它必须是 XSD 1 架构吗?或者您可以使用 Schematron 还是使用带有断言的 XSD 1.1?
  • @MartinHonnen 您的意思是 2 个 XSD 用于第一次验证(允许的字符)?至于您的其他建议,我不希望将其他框架放入图片中,这会增加额外的工作量(学习曲线、实施、资源),因为此过程只是要求极高的消息传递服务管道中的一小部分。谢谢你的建议,我去看看。
  • 好吧,作为最后的手段,我正在考虑编写一小段 XSLT 来转换 XML 并在验证失败时输出成功消息或有问题的元素列表。但是,我想知道这是否可以使用 XSD。

标签: xml xsd schema


【解决方案1】:

Schematron 使用 XPath 或 XSLT 2 或 3 可能是这样的

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

【讨论】:

  • 这是完美的,它是 xsl 和 xsd 的组合,如果只是没有 Schematron 的情况(占用空间大)。尽管我的解决方案通过 XSLT 和自定义扩展功能(请参阅我上面的编辑),但我投票赞成这是一个有效的答案。
  • @Agoun,因为您似乎使用了 XSLT 2,您可以在不需要使用扩展函数的情况下支持正则表达式我不太明白为什么在您的方法中需要它。至于 Schematron 扩展工具链,是的,我知道只使用 XSD 模式来解决它是可取的,但我看不到方法,Michael Kay 的回答表明他也没有看到。至于只使用 XSLT,在 XSLT 3 中除了 XSLT 1 和 2 xsl:message 之外,还有一个 xsl:assert 指令,因此当然应该可以消除 Schematron 并使用 XSLT 进行诊断。
  • 好吧,我错过了 XSLT 2 中的这个“匹配”功能,谢谢。我必须检查的是如何将正则表达式作为参数传递。逃还是不逃?应该从系统中获取正则表达式。 xsl:message 写入标准输出,所以我也必须抓住它。
【解决方案2】:

如果这是混合内容,那么您绝对不能这样做(没有 XSD 1.1 断言) - 无法限制混合内容中出现的文本。

使用简单类型,您可以使所有(基于字符串的)简单类型派生自 xs:string 的子类型,并具有适当的模式限制,但如果这对您的口味来说重构太多,那么您将拥有寻找另一种方式。

如果您要独立于 XSD 验证进行单独的验证传递,那么 XSD 似乎不是合适的技术。如果您在 Java 世界中,我会很想使用放置在 XML 解析器和模式验证器之间的 SAX 过滤器来做到这一点。

【讨论】:

  • Michael,谢谢你,事实上我没有发现任何涉及 XSD 的东西,除了弄乱原型,我不会那样做。但是,我找到了一种简单的方法(对于那些可以处理 xslt 和外部函数的人),并且它适用于任何类型的 XML,无论命名空间。此外,它返回一个未通过此验证的元素列表(无效字符),以便系统可以优雅地处理和通知发现的问题和位置。我会在找到空闲时间后立即发布我的解决方案。
猜你喜欢
  • 2018-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多