XSD使用命名空间属性验证XML

时间:2017-10-20 08:18:38

标签: xml validation xsd

我需要创建一个XSD来验证以下XML:

<?xml version="1.0" encoding="UTF-8"?>
<thing:cardAuthRequestResponse 
    xmlns:thing="http://www.thing.com/thing" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <thing:request xsi:type="thing:GiftCardBalanceRequest" />
</thing:cardAuthRequestResponse>

我尝试了各种在线XSD生成器和验证器(例如https://www.freeformatter.com/xml-validator-xsd.html&amp; https://www.freeformatter.com/xsd-generator.html),但没有人生成一个XSD来验证XML,但有各种错误。问题出在名称空间类型属性:xsi:type

以下内容将验证(xsi命名空间已从type属性中删除):

INPUT:

<?xml version="1.0" encoding="UTF-8"?>
<thing:cardAuthRequestResponse 
    xmlns:thing="http://www.thing.com/thing" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <thing:request type="thing:GiftCardBalanceRequest" />
</thing:cardAuthRequestResponse>

XSD

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.thing.com/thing" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="cardAuthRequestResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="request">
          <xs:complexType>
            <xs:simpleContent>
              <xs:extension base="xs:string">
                <xs:attribute type="xs:QName" name="type"/>
              </xs:extension>
            </xs:simpleContent>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

我是否可以更改XSD以使用namespaced type属性验证XML,或者是否存在基本上与XML无关的内容?

3 个答案:

答案 0 :(得分:0)

似乎您的xml正在尝试创建xsd类型的动态列表,然后包含内容并且可以进行验证。这与xml没有关系,但如果自动生成的模式可以理解这个目标,我会感到惊讶。

我重新设计了一些命名空间,让它们实际链接并协同工作,以创建一个可能看起来如何的示例。

XSD - 只需定义您有一个cardAuthRequestResponse,其中包含任意数量的request元素。这些可以是xs:anyType

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://www.enactor.com/retail">
    <xs:element name="cardAuthRequestResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="request" type="xs:anyType" maxOccurs="unbounded" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="GiftCardBalanceRequest">
    </xs:complexType>

    <xs:complexType name="AgeRequest">
        <xs:sequence>
            <xs:element name="age">
                <xs:simpleType>
                    <xs:restriction base="xs:nonNegativeInteger" />
                </xs:simpleType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

这将允许您验证此xml

<?xml version="1.0" encoding="UTF-8"?>
<retail:cardAuthRequestResponse
        xmlns:retail="http://www.enactor.com/retail"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <retail:request xsi:type="retail:GiftCardBalanceRequest" numRequests="2" />
    <retail:request xsi:type="retail:AgeRequest" numRequests="2">
        <retail:age>2</retail:age>
    </retail:request>
</retail:cardAuthRequestResponse>

现在,您可以看到我现在编写的AgeRequest允许您验证这些特定元素。

现在这个方法有1个缺点,request扩展了xs:anyType。这意味着你可以放<retail:request><foobar/>2</retail:request>,它也有效。但是,如果您对样本进行了简化以便简化,那么您可能需要修复它。

方法2

这会使您的xsd更强类型,并限制request可以定义的类型。它允许您创建所有request元素的基本属性和元素要求。例如:

XSD - 只需定义您有一个cardAuthRequestResponse,其中包含任意数量的request元素。这些可以是retail:baseRetailRequest

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:retail="http://www.enactor.com/retail"
           targetNamespace="http://www.enactor.com/retail">
    <xs:element name="cardAuthRequestResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="request" type="retail:baseRetailRequest" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="baseRetailRequest">
        <xs:attribute name="numRequests" type="xs:nonNegativeInteger" use="required"></xs:attribute>
    </xs:complexType>


    <xs:complexType name="GiftCardBalanceRequest">
        <xs:complexContent>
            <xs:extension base="retail:baseRetailRequest">
                <xs:sequence></xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:complexType name="AgeRequest">
        <xs:complexContent>
            <xs:extension base="retail:baseRetailRequest">
                <xs:sequence>
                    <xs:element name="age">
                        <xs:simpleType>
                            <xs:restriction base="xs:nonNegativeInteger" />
                        </xs:simpleType>
                    </xs:element>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
</xs:schema>

现在每个<request>都需要为其定义numRequests属性。如果您有一个必须填写的基本请求,这可能很有用。例如:

<?xml version="1.0" encoding="UTF-8"?>
<retail:cardAuthRequestResponse
        xmlns:retail="http://www.enactor.com/retail"
        xmlns:thing="http://www.thing.com/thing"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <retail:request xsi:type="thing:GiftCardBalanceRequest" numRequests="2" />
    <retail:request xsi:type="thing:AgeRequest" numRequests="2">
        <thing:age>2</thing:age>
    </retail:request>
</retail:cardAuthRequestResponse>

答案 1 :(得分:0)

首先,您的XSD不是有效的架构,因为xs:attribute的name属性必须是NCName(因此xsi:type无效)。

通常,如果要允许与模式的targetNamespace不同的名称空间中的属性,您可以在具有自己的targetNamespace的不同模式文档中声明它,导入该模式文档,并使用“ref”引用该属性“而不是”名字“。

但是xsi:type是特殊的:它隐含地声明并隐式允许任何元素。因此,您只需从架构中删除对xsi:type的引用即可。

下一个问题是您的实例文档位于命名空间http://www.thing.com/thing中,而您的架构定义了命名空间http://www.enactor.com/retail。我不确定这是在发布您的问题时发生的简单复制/粘贴错误,还是您从根本上无法理解命名空间在确保模式有效性方面的重要性。

如果我解决了这个问题,我就会遗漏一个错误:

test.xml第6行第62列的验证错误:   FORG0001:xsi:type属性中指定的未知类型{thing:GiftCardBalanceRequest}

这是因为xsi:type的语义要求其值是模式中声明的类型的名称,并且您的模式不包含此类型。

哦,没有必要尝试将xsi:type的声明写入任何文档的模式;模式验证器使用它来为元素选择类型(具体来说,覆盖默认类型赋值),但不会根据元素的声明进行验证。为xsi命名空间编写模式文档并不是错误,但任何符合标准的处理器都不会使用它。

答案 2 :(得分:0)

  

...... XML有什么根本无效的吗?

没有XML实例可以构建一个有效的模式。从来没有&#34;从根本上无效&#34; XML文档。

在目前的情况下,您应该花一两个小时来阅读xsi:type属性的使用;它用于指定用于验证的模式中存在的类型的名称,以覆盖分配给该元素的默认类型。

使实例有效所需的最低要求是具有

的模式
  1. 元素的声明,其限定名称为{http://www.thing.com/thing}cardAuthRequestResponse,允许有效元素实例包含名为{http://www.thing.com/thing}request的单个元素作为内容;
  2. 元素{http://www.thing.com/thing}request的声明,它为其指定了一些命名类型,不会阻止派生类型的派生;和
  3. 名为{http://www.thing.com/thing}GiftCardBalanceRequest的类型的顶级类型定义,该类型派生自第2项中指定给元素{http://www.thing.com/thing}request的类型。
  4. 例如:

    <xsd:schema targetNamespace="http://www.thing.com/thing"
                xmlns:thing="http://www.thing.com/thing"
                xmlns:xsd="..."
                ... >
      <xsd:element name="cardAuthRequestResponse"/>
      <xsd:element name="request"/>
      <xsd:type name="GiftCardBalanceRequest"/>
    </
    

    用于生成模式的工具可能不适用于包含xsi:type属性的实例,这并不奇怪:xsi:type用于指向现有模式中的类型,如果模式已存在,则工具可能很好奇为什么有人在运行它。

    如果您自己创建XML,为什么使用xsi:type?

    如果您从其他人那里收到XML,您是否询问了架构文档的位置?