Может ли relaxng указать неупорядоченный набор элементов с одинаковыми именами, но разными атрибутами?
Я работаю над автоматизацией тестирования API, который принимает и возвращает XML, поэтому я хочу как можно больше перевести документированные возвращаемые данные API в схему. Я выбрал RelaxNG для этой задачи, основываясь на простоте использования и обучения.
Прежде чем я добавлю всю информацию, вот вопрос:
Можно ли описать "неупорядоченный набор элементов с одинаковыми именами, но разными атрибутами"?
Вот пример объекта, для которого у меня возникают проблемы при описании:
<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>
Объекты ссылок - это то, от чего я зацикливаюсь. Вот проблема:
- Порядок элементов внутри элемента не гарантируется, поэтому я пытаюсь поместить все элементы в
<interleave>
состав. - Там будет несколько
<link>
элементы внутри<item>
с разными наборами атрибутов (т.е.<item>
ДОЛЖНЫ иметь ссылку "self", ссылку "download" и ссылку "relatedData", чтобы быть действительными). - Требуется один из каждого типа ссылки, но, опять же, порядок не гарантируется.
Я попытался описать схему так:
<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>
ссылки 'link' определены в другом месте следующим образом:
<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>
Парсер это не радует - от цзин я получаю error: the element "link" can occur in more than one operand of "interleave"
, Я могу видеть, к чему это приводит, но я надеялся, что он сможет обработать идею "элементов с одинаковыми именами, но разными атрибутами" как уникальных предметов.
Перемещение ссылки refs из interleave заставляет ее анализировать, но я буду ждать, когда валидатор взорвется, когда порядок в возвращаемых данных изменится.
Есть идеи или это невозможно? Существует ли внутренняя проблема с XML, который я обрабатываю, который потребует от меня переместить часть этого к более высокой логике обработки в моем тестовом приложении (вручную проверять каждый тип ссылки после выполнения более общей проверки XML?)
2 ответа
Похоже, вы наткнулись на ограничение чередования в RELAX NG. Я попытался бы сделать это в Schematron или, возможно, в комбинации RELAX NG и Schematron.
Вот фрагмент, который проверяет ваш <link>
элементы, использующие версию Schematron, поддерживаемую 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>
Посмотрите, поможет ли следующая схема
<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>