如何扩展Atom架构?

时间:2014-08-08 10:44:21

标签: xml xsd atom-feed

我正在设计一个XML产品Feed,许多网店都会使用它来发布他们的产品数据。此产品Feed的结构将基于Atom XML standard,类似于Google's Atom product feed。我将发布一个可用于验证产品Feed的XSD文件。

基本上,每个<entry>元素都代表一个产品。我需要在<entry>元素中添加一些子元素,其中包含产品价格,运费等数据。

问题在于创建XSD文件。我不确定如何扩展Atom标准,以便我可以将子元素添加到<entry>。目前我只是将额外元素定义为顶级元素,但这不允许我指定事件指标(minOccursmaxOccurs)。

我想要做的是指定每个<entry>元素中需要的多个元素。它们可以是我的模式引入的新元素(例如保存产品价格的<price>元素),以及现有的Atom元素(例如由Atom定义的<link>元素,但是不是必需的。)

以下是我当前 product-feed.xsd 的简化版本:

<?xml version="1.0" encoding="UTF-8"?>

<xs:schema 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://example.com/schemas/product-feed"
    xmlns:p="http://example.com/schemas/product-feed"
    xmlns:atom="http://www.w3.org/2005/Atom"
    elementFormDefault="qualified">

  <xs:element name="brand" type="xs:string" />

  <xs:element name="price" type="p:money" />

  <xs:element name="shipping" type="p:money" />

  <xs:complexType name="money">
    <xs:simpleContent>
      <xs:extension base="xs:decimal">
        <xs:attribute name="currency" 
                      type="p:currency" 
                      use="required" />
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

  <xs:simpleType name="currency">
    <xs:restriction base="xs:string">
      <xs:enumeration value="EUR" />
      <xs:enumeration value="USD" />
      <xs:enumeration value="GBP" />
    </xs:restriction>
  </xs:simpleType>

</xs:schema>

以下是xml Feed的示例:

<?xml version="1.0" encoding="UTF-8"?>

<feed xmlns="http://www.w3.org/2005/Atom"
      xmlns:p="http://example.com/schemas/product-feed"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <title>Example Store</title>
  <link href="http://www.example-store.com/" rel="self" />
  <updated>2014-08-08T10:44:20Z</updated>

  <entry>
    <title>Foo</title>
    <link href="http://www.example-store.com/products/foo.html" />
    <p:price currency="EUR">32.95</p:price>
    <p:shipping currency="EUR">6.75</p:shipping>
  </entry>

  <entry>
    <title>Bar</title>
    <link href="http://www.example-store.com/products/acme-bar.html" />
    <p:brand>Acme</p:brand>
    <p:price currency="EUR">12.50</p:price>
    <p:shipping currency="EUR">6.75</p:shipping>
  </entry>

</feed>

如何扩展Atom架构,使我的自定义元素只允许在<entry>元素中,并且我可以定义它们可能出现的次数?

我能想到的唯一替代解决方案是复制Atom架构定义文件(例如this one),并修改它(添加我自己的元素,并更改我想要的Atom元素) )。这感觉不太好(我不会再扩展Atom,我只是创建一个全新的模式)所以我希望有更好的解决方案。

1 个答案:

答案 0 :(得分:3)

对解释的完整答案将需要比现在更多的时间,但可以快速勾勒出解决方案的基本要素。

首先,您指向的XSD有许多问题,如RFC 4287中所述的Atom格式的表示。

  • 它使用重复的选择组来表示Relax NG交错组,这意味着它不会在Atom人员构造中强制执行规范的RNG模式的任何基数约束,原子:feed element,atom:entry元素或atomSource。

    在XSD 1.1架构中,最好用all-groups表示。在XSD 1.0模式中,对单个元素强制执行最小和最大出现限制将需要相当冗长的序列选择(它们本身具有嵌套选择组),这是可行的,但是构造起来有点繁琐。

  • 它对电子邮件地址使用正则表达式模式,既不符合Atom规范的散文(表示地址必须符合RFC 2922),也不符合RNG模式(使用非常简单的表达式{ {1}}。

    生成与RFC 2822的".+@.+"生成相匹配的正则表达式,从而强制执行A​​tom规范的规则是不可能的。 (合法的addr-spec值的集合是无上下文的,不是常规的,因为RFC 2822注释嵌套。)使用正则表达式对其进行近似是可能的,但是除非你系统地进行,否则有点耗时且容易出错。最简单的解决方案是遵循Atom规范中RNG模式的示例,只需要一个字符串,其中至少有一个at-sign既不在开头也不在结尾。

所以你的第一步是创建(或找到)一个XSD,它可以更好地表示Atom文档语法。

那么你的三个选择是:

  • 修改架构文档(添加注释以描述您的更改并将未来读者指向您从中开始的基本架构文档)以导入命名空间并将所需的特定元素添加到atom的内容模型中:entry

    这样做的好处是操作简单。它的缺点是,您在Atom规范中修改Atom语言与其定义之间的关系只能与您的自然语言注释一样清晰。您担心在这种情况下您不会真正扩展Atom语言;我认为您正在扩展Atom语言,但您通过为Atom扩展独立的架构来注意到您没有这样做。这可能是一个劣势。

  • 使用xsd:redefine重新定义atom:entry元素的类型,方法是将通配符限制为要查看的元素。您的重新定义必须是对基本模式中定义的类型的有效限制(但XSD不保证符合模式的符合重新定义将是一致的模式,这使得重新定义的约束对某些用户来说似乎毫无意义)。

    这具有符合XSD 1.0的优点;它的缺点可能是相当棘手且容易出错(就在上周,我听到一位着名的文档设计师在公开场合表示他从来没有能够让XSD重新定义工作)。它的缺点是已知XSD 1.0处理器具有不一致的重新定义实现。 (应该注意的是,这种不一致性主要出现在涉及多个冗余导入,包括和重新定义的情况中,并且不应该出现在您描述的直接情况中)。

  • 如果您可以使用XSD 1.1,请使用xsd:override修改atom:entry的内容模型。

    这样做的好处是可以将更改与基本模式分开,并且比xsd:redefine更容易指定。但它确实需要XSD 1.1,您希望使用的工具链可能支持也可能不支持。