Работа с вложенными предикатами XPath ... - PullRequest
8 голосов
/ 08 июня 2009

Все отличные ответы! Но вопрос заслуживает уточнения ...

У меня есть следующий пример XML ...

<objects>
    <object objectId="1123" ... />
    <properties refObjectId="1123" ... />
    <properties refObjectId="1123" refPropertyId="2311" ... />
    <properties refObjectId="1123" refPropertyId="4611" ... />
    <object objectId="2123" ... />
    <properties refObjectId="2123" refPropertyId="4311" ... />
    <properties refObjectId="2123" refPropertyId="8611" ... />
    ....
</objects>

... и следующий запрос XPath ...

//object[//properties[@refObjectId=@objectId and not(@refPropertyId)]]

Я думал, что этот запрос вернет все узлы object, где есть узел properties с атрибутом refObjectId, равным атрибуту objectId узла object и отсутствием refPropertyId атрибут ... а именно объект 1123, а не объект 2123 ... но это не так. Кажется, что @objectId во вложенном предикате не относится к атрибуту objectId узла object.

Есть идеи? Я знаю, что структура XML не является вложенной, как вы ожидаете, но есть причины для этой структуры.

Ответы [ 4 ]

7 голосов
/ 08 июня 2009

Как правило, вам следует избегать использования //, где вы можете. Я хотел бы перефразировать:

//object[../properties/@refObjectId=@objectId]

В предоставленном выражении ваш вложенный предикат фактически проверяет наличие

//properties/@refObjectId=//properties/@objectId 

из которых нет ни одного.

Надеюсь, это поможет!

РЕДАКТИРОВАТЬ: Поскольку вопрос был обновлен здесь обновленный ответ: Вы добавили: «Кажется, @objectId во вложенном предикате не ссылается на атрибут objectId узла объекта». Вы абсолютно правы! Так что давайте исправим это!

//object[../properties[not(@refPropertyId)]/@refObjectId=@objectId]

Это должно быть ближе к тому, что вы ищете!

0 голосов
/ 09 июня 2009

Предполагая, что все <properties> узлы, которые принадлежат данному <object> на самом деле , следуют за этим объектом (ваш ввод, кажется, подразумевает это), вы можете сделать:

/objects/properties[
  @refObjectId = preceding-sibling::object[1]/@objectId
  and 
  not(@refPropertyId)
]/preceding-sibling::object[1]

Это должно работать очень хорошо.

Если вы оказались в XSLT, все станет намного проще:

<xsl:key name="kPropertiesByObjectId" match="properties" use="@refObjectId" />

и

<xsl:template match="object">
  <!-- This tests for an empty node-set. Non-empty node sets can only happen
       for objects with at least one <properties> node without @refPropertyId -->
  <xsl:if test="key('kPropertiesByObjectId', @objectId)[not(@refPropertyId)]">
    <xsl:copy-of select="." />
  </xsl:if>
</xsl:template>

В случае XSLT порядок узлов объектов и объектов становится неактуальным.

0 голосов
/ 08 июня 2009

Это должно работать:

//objects/object[@objectId = ../properties/@refObjectId]

Я не уверен, как твой xml. Однако, если это в следующем формате:

<objects>
    <object objectId="1111" />
    <properties refObjectId="1111" />
    <object objectId="2111" />
    <properties refObjectId="3111" />
    <object objectId="4111" />
    <properties refObjectId="5111" />
    <object objectId="6111" />
    <properties refObjectId="4111" />
    <object objectId="7111" />
    <properties refObjectId="7111" />
</objects>

Тогда вы должны использовать следующий xpath, чтобы получить только объекты 1111 и 7111. Результат не должен включать 4111, потому что свойства, где refObjectId = 4111, не сразу следуют за объектом, objectId = 4111.

//objects/properties[@refObjectId = preceding::object[1]/@objectId]/preceding::object[1]
0 голосов
/ 08 июня 2009

Попробуйте это:

   //objects[object/@objectId = properties/@refObjectId]/object
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...