Can relaxng specify an unordered set of elements with the same name, but different attributes?

泄露秘密 提交于 2019-12-01 03:42:36

问题


Im working to automate the testing of an API which takes and returns XML, so I want to translate the documented return data of the API into schema as much as possible. I chose RelaxNG for this task based on ease of use and learning.

Before I throw in all the info, here's the question:

Is it possible to describe "unordered set of elements, with the same name but different attributes" ?

Here is a sample object for what I'm having trouble describing:

<item>
    <id>d395136e-d060-4a6e-887c-c0337dd7ad09</id>
    <name>The item has a name</name>
    <link rel="self" type="type1" href="url" />
    <link rel="download" type="type2" href="url" />
    <link rel="relatedData" type="type3" href="url" />
</item>

The link objects are the bit that I'm getting hung up on. Here is the problem:

  • The order of elements inside item is not guaranteed, so I am trying to put all elements in <interleave> structure.
  • There will be multiple <link> elements inside <item>, with different sets of attributes (ie, <item> MUST have a 'self' link, a 'download' link, and a 'relatedData' link to be valid).
  • One of each link type is required, but again order is not guaranteed.

I tried to describe the schema like so:

<element name="item">
    <interleave>
        <element name="id"><text/></element>
        <element name="name"><text/></element>
        <ref name="selfLink"/>
        <ref name="launchLink"/>
        <ref name="thumbnailLink"/>
    </interleave>
</element>

the 'link' references are defined elsewhere like so:

 <define name="selfLink">
 <element name="link">
     <attribute name="href"><text/></attribute>
     <attribute name="rel"><value>self</value></attribute>
     <attribute name="type"><value>type1</value></attribute>
 </element>
 </define>

The parser is not pleased about this - from jing I get error: the element "link" can occur in more than one operand of "interleave". I can see what its getting at but I hoped it could handle the idea of 'elements with the same name but different attributes' as unique items.

Moving the link refs out of interleave gets it to parse, but I'll be waiting for the validator to blow up whenever the order changes in the returned data.

Any ideas, or is this impossible? Is there an inherent issue with the XML I am processing that will require me to move some of this up to higher processing logic in my test application (manually check for each link type after running a more generic XML validation?)


回答1:


It looks like you have stumbled upon a restriction on interleave in RELAX NG. I would try to do this in Schematron, or perhaps a combination of RELAX NG and Schematron.

Here is a snippet that checks your <link> elements using the version of Schematron that is supported by Jing:

<schema xmlns="http://www.ascc.net/xml/schematron">
  <pattern name="link pattern">
    <rule context="item">
      <assert test='count(link) = 3'>There must be 3 link elements.</assert>
      <assert test="count(link[@rel = 'self' and @type ='type1']) = 1">There must be 1 link element wwhere @rel='self' and @type='type1'.</assert>
      <assert test="count(link[@rel = 'download' and @type ='type2']) = 1">There must be 1 link element where @rel='download' and @type='type2'.</assert>
      <assert test="count(link[@rel = 'relatedData' and @type = 'type3']) = 1">There must be 1 link element where @rel='relatedData' and @type='type3'.</assert>
    </rule>
  </pattern>
</schema>



回答2:


See if the following schema helps

<grammar xmlns="http://relaxng.org/ns/structure/1.0">
<start>
    <element name="item">
        <interleave>
            <element name="id"><text/>
            </element>
            <element name="name"><text/></element>
            <oneOrMore>
                <ref name="link"/>
            </oneOrMore>
        </interleave>
    </element>
</start>

<define name="link">
    <element name="link">
        <attribute name="href"/>
        <choice>
            <group>
                <attribute name="rel"><value>self</value></attribute>
                <attribute name="type"><value>type1</value></attribute>
            </group>
            <group>
                <attribute name="rel"><value>download</value></attribute>
                <attribute name="type"><value>type2</value></attribute>
            </group>
            <group>
                <attribute name="rel"><value>relatedData</value></attribute>
                <attribute name="type"><value>type3</value></attribute>
            </group>
        </choice>
    </element>
</define>
</grammar>


来源:https://stackoverflow.com/questions/11786196/can-relaxng-specify-an-unordered-set-of-elements-with-the-same-name-but-differe

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!