Как выбрать узлы, принадлежащие к той же группе в xpath? - PullRequest
1 голос
/ 19 октября 2011

У меня есть документ XML, который действителен для схемы XML. Схема XML имеет элементы группы (xs: group). Эти группы состоят из других определенных элементов. Как я могу написать выражение XPath, которое даст мне всех членов указанной группы?

Есть идеи?

@ Стив:

предположим, что моя xml-схема определила 4 элемента ( elem1, elem2, elem3, elem4 ). кроме того, 2 группы определены следующим образом:

group1: (elem1 | elem2 | elem3)
group2: (elem1 | elem4)

Надеюсь, вы знаете некоторые регулярные выражения. если нет, то «group2: (elem1 | elem4)» просто означает, что group2 состоит из EITH elem1 ИЛИ elem4.

У меня вопрос: есть ли у меня XML-документ, такой как:

<elem1/>
<elem2/>
<elem3/>
<elem4/>
<elem2/>
<elem1/>
<elem3/>

Как я могу перечислить элементы в этом документе, которые относятся, скажем, к group1

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> 
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="elem0"/>
                <xs:choice minOccurs="0" maxOccurs="unbounded">
                    <xs:group ref="A1"/>
                    <xs:group ref="A2"/>
                </xs:choice>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

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

    <xs:group name="A1">
        <xs:choice>
            <xs:element ref="elem10"/>
            <xs:element ref="elem11"/>
        </xs:choice>
    </xs:group>

    <xs:element name="elem10" type="xs:string"/>
    <xs:element name="elem11" type="xs:string"/>

    <xs:group name="A2">
        <xs:choice>
            <xs:element ref="elem20"/>
            <xs:element ref="elem21"/>
            <xs:element ref="elem22"/>
            <xs:element ref="elem23"/>
        </xs:choice>
    </xs:group>

    <xs:group name="CE">
        <xs:choice>
            <xs:element ref="elem30"/>
            <xs:element ref="elem31"/>
            <xs:element ref="elem32"/>
        </xs:choice>
    </xs:group>

    <xs:group name="E">
        <xs:choice>
            <xs:element ref="elem30"/>
            <xs:element ref="elem40"/>
        </xs:choice>
    </xs:group>

    <xs:element name="elem20">
        <xs:complexType>
            <xs:sequence>
                <xs:group minOccurs="2" maxOccurs="unbounded" ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem21">
        <xs:complexType>
            <xs:sequence>
                <xs:group minOccurs="2" maxOccurs="2" ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem22">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="elem40"/>
                <xs:group ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem23">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="elem40"/>
                <xs:element ref="elem40"/>
            </xs:sequence>
            <!-- <xs:attribute name="prop" use="required" type="xs:NMTOKEN"/> -->
        </xs:complexType>
    </xs:element>

    <xs:element name="elem31">
        <xs:complexType>
            <xs:sequence>
                <xs:group minOccurs="0" maxOccurs="unbounded" ref="CE"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem32">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="CE"/>
            </xs:sequence>
            <!-- <xs:attribute name="prop" use="required"/> -->
        </xs:complexType>
    </xs:element>

    <xs:element name="elem30">
        <xs:complexType>
            <xs:attribute name="name" use="required"/>
        </xs:complexType>
    </xs:element>

    <xs:element name="elem40">
        <xs:complexType>
            <xs:attribute name="name" use="required"/>
        </xs:complexType>
    </xs:element>
</xs:schema>

1 Ответ

2 голосов
/ 19 октября 2011

ОК ... есть несколько вещей, которые, я думаю, нам нужно прояснить в вашем примере - потому что, хотя они могут показаться незначительными, на самом деле это не так - и, если вы следуете правилам, это Должно быть понятно, как создать выражение XPath (я покажу примеры того, как создать базовые выражения XPath, принимая во внимание группы для допустимых схем, и в чем заключается проблема с вашим примером).

Давайте рассмотрим это поэтапно.

Группы с последовательностями

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

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="group1"/>
                <xs:group ref="group2"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:group name="group1">
        <xs:sequence>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
            <xs:element name="elem3"/>
        </xs:sequence>
    </xs:group>
    <xs:group name="group2">
        <xs:sequence>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
        </xs:sequence>
    </xs:group>
</xs:schema>

В этом случае важно отметить, что у нас есть последовательность из group1, за которой следует group2 обе из которых последовательности элементов.

С sequence , (и без атрибута minoccurs='0' на любом из элементов group - что в любом случае будет недопустимым, как я объясню позже), выбор необходимых элементов тривиален.

Чтобы выбрать все элементы group1, мы могли бы просто использовать следующий XPath:

/root/(elem1[1]|elem2[1]|elem3)

Это работает, потому что мы знаем, что полученный XML будет всегда быть:

<root>
     <elem1 />
     <elem2 />
     <elem3 />
     <elem1 />
     <elem2 />
</root>

Итак, все в порядке. Мы всегда можем выбрать первые elem1, первые elem2 и elem3.

Группы с выбором

Предположим, что вместо групп, содержащих последовательности, вместо них содержалось вариантов . Схема выглядит следующим образом:

(Это больше похоже на схему, которую вы положили в своем примере, где «группа2 состоит из ЛИБО элемент1 ИЛИ элемент4».)

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="group1"/>
                <xs:group ref="group2"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:group name="group1">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
            <xs:element name="elem3"/>
        </xs:choice>
    </xs:group>
    <xs:group name="group2">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
        </xs:choice>
    </xs:group>
</xs:schema>

В этом случае XPath все еще тривиально построить, потому что мы знаем, что будет только два элемента, и первый будет принадлежать group1, а второй будет принадлежать group2, вот так:

<root>
     <elem2 />
     <elem1 />
</root>

Итак, group1 XPath еще проще:

/root/*[1]

Уникальная атрибуция частиц

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

В вашем примере вы предложили следующую схему:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:group ref="group1" maxOccurs="unbounded"/>
                <xs:group ref="group2" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:group name="group1">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
            <xs:element name="elem3"/>
        </xs:choice>
    </xs:group>
    <xs:group name="group2">
        <xs:choice>
            <xs:element name="elem1"/>
            <xs:element name="elem2"/>
        </xs:choice>
    </xs:group>
</xs:schema>

Эта схема недопустима. (обратите внимание на добавление атрибута maxOccurs="unbounded" в группы). Это похоже на ваш пример, где вы показываете несколько элементов из одной группы).

Почему? Ну, потому что это создает потенциальную неопределенность в результирующем XML.

Например, как мы должны проанализировать следующий экземпляр XML:

<root>
     <elem2 />
     <elem1 />
     <elem1 />
     <elem2 />
</root>

Это:

  • group1, group1, group1, group1
  • или group1, group1, group1, group2
  • или group1, group1, group2, group1
  • или group1, group2, group1, group1
  • ...

Мы просто не знаем.

Но разработчики XML-схем подумали об этом и разработали правило для этого:

http://en.wikipedia.org/wiki/Unique_Particle_Attribution

И ваша гипотетическая схема нарушает это правило.

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

В вашем примере, если в xml нет элементов 3 или 4, на самом деле совершенно невозможно определить, где заканчивается group1 и group2.

Теперь, если все, что вам нужно, это выбрать элементы с определенным именем, вы можете сделать это легко:

/root/(elementName1|elementName2|elementName3)

выберет все элементы в root с именами elementName1 или elementName2 или elementName3.

Итак, в вашем примере что-то вроде: (elem1|elem2|elem3) было бы просто отлично.

Но это не то, что вы спросили. То, что вы спросили, было о выборе по группе - и приведенный вами пример лишил возможности дать вам реальный ответ для по группе .

Если у вас есть реальная , действительная схема и вам нужна помощь в создании XPath, вставьте эту схему, и я буду рад Помогите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...