2016-04-16 5 views
2

Я пытаюсь написать RelaxNG схему, которая имеет следующие правила:Экспресс рекурсивных ссылок в наборе повторяющихся упорядоченных элементов

  1. line элемент может содержать ноль или более a и b элементы.
  2. Каждый элемент a должен иметь соответствующий элемент b и наоборот.
  3. a элементы должны всегда предшествовать их сопоставлению b элементов.

Таким образом, следующие должны все считаться действительными:

<line><a/><b/></line> 

<line><a/><a/><b/><b/></line> 

<line><a/><a/><b/><a/><b/><b/></line> 

Между тем, следующие все недействителен:

<line><b/><a/></line> 

<line><a/><a/><b/></line> 

<line><a/></line> 

<line><b/></line> 

Как это может быть выражено в RelaxNG? Моя первая мысль была создать рекурсивную ссылку, например, так:

element line { pair* }+ 

pair = a, pair?, b 

a = element a { empty } 
b = element b { empty } 

Однако Цзин считает, что это «плохо рекурсивная ссылку на„пару“». Я не могу за всю жизнь понять, как это решить! Есть идеи?

ответ

1

Образцы Relax NG (например, модели контента DTD и XSD) являются, по существу, регулярными выражениями; они определяют регулярные языки над множеством имен элементов и text. Для сопоставления a/b, которое вы ищете, требуется контекстная грамматика; поэтому он не может быть определен в Relax NG.

Можно, конечно, приблизиться. Если вы ожидаете, что на практике у вас никогда не будет более пяти пар а/б (или, точнее: не более пяти элементов a, для которых вы еще не видели соответствия b), вы можете определить любой из следующих языков.

Первое:

pair0 = (a, b)* 
pair1 = (a, pair0, b)* 
pair2 = (a, pair1, b)* 
pair3 = (a, pair2, b)* 
pair4 = (a, pair3, b)* 
pair5 = (a, pair4, b)* 
pair6 = (a, pair5, b)* 
pair7 = (a, pair6, b)* 
pair8 = (a, pair7, b)* 
pair9 = (a, pair8, b)* 
pair = (a, pair9, b)* 

Это определяет подмножество вашего языка, который строго соблюдает свои два правила, но не может справиться с а/б пар гнездятся более 10 глубиной. (Или 11, в зависимости от того, что вы считаете.) Каждый документ, принятый этим определением, будет членом того языка, который вы действительно хотите, но не каждый член языка будет принят.

Если отвергая действительные экземпляры языка не является приемлемым, вы можете определить шаблоны, как указано выше, но переопределить pair0 как:

pair0 = (a, (a|b)*, b)* 

Это определяет супернабор языка, в котором правила применяются для/b до максимального уровня вложенности, но в тех случаях, когда правила прекращаются, когда уровень вложенности превышает этот максимум. В этом случае каждый член желаемого языка будет принят, но так будет и какой-то мусор, которого не должно быть.

Являются ли эти приближения для использования в вашем приложении, я оставляю вам решение.

Если приближения неприемлемы, вам может быть проще получить то, что вам нужно, определив XML по-разному.

Одно простое изменение было бы обернуть каждый соответствие a и b в элементе (который я буду называть e):

element line { pair* } 
a = element a { empty } 
b = element b { empty } 
pair = element e { a, pair*, b } 

Теперь срок действия документа обеспечивает очень простую гарантию того, что a элементы и b элементы соединяются по мере необходимости и что каждый a предшествует его соответствию b.

Учитывая, что a и b пустуют, что каждый a немедленно следует начальный тег для e, и что каждый b непосредственно предшествует конечного тега для того же самого e элемента, вы можете полностью заменить a и b элементы пусковая теги для e и конечных тегов для e, соответственно, и объявить line как

element line { e* } 
e = element e { e* } 

SAX интерфейсы, интерфейсы DOM, XSLT, XQuery, и любой другой метод, который я знаю га ndling XML упрощает сопоставление действий с началом и концом элемента, поскольку он связан с действиями с пустым элементом.

Ваши действительные примеры становятся:

<line><e></e></line> 
<line><e><e></e></e></line> 
<line><e><e></e><e></e></e></line> 

и недействительные примеры становятся не wellformed данных.