XPath 1 запрос - PullRequest
       38

XPath 1 запрос

1 голос
/ 13 февраля 2009

Я опубликовал похожий вопрос и получил очень полезный ответ. Теперь вопрос немного другой, поэтому я выкладываю его. Я уточняю, что это вопрос, связанный с XPath 1. Это содержимое моего XML-файла:

<?xml version="1.0" encoding="ISO-8859-1"?>
<mainNode>
    <subNode>
        <h hm="08:45">
            <store id="1563">Open</store>
        </h>
        <h hm="13:00">
            <store id="1045">Open</store>
            <store id="763">Open</store>
            <store id="1047">Open</store>
        </h>
        <h hm="16:30">
            <store id="1045">Open</store>
            <store id="763">Open</store>
            <store id="1047">Open</store>
        </h>
        <h hm="20:00">
            <store id="1045">Open</store>
            <store id="1043">Open</store>
            <store id="1052">Open</store>
        </h>
        <h hm="22:00">
            <store id="763">Open</store>
        <store id="1052">Open</store>
        </h>
    </subNode>
</mainNode>

Моя программа получает текущее время: если я получаю 12.40, я должен получить идентификатор всех магазинов следующего ччм (13.00): эта проблема была решена.

После извлечения данных со вторым запросом XPath я должен получить информацию до того момента, когда в течение текущего дня (представлением которого является файл XML) будет открыто одно хранилище. Итак, представьте, что магазин - это магазин, идентифицированный с id = 1045, а сейчас 12.40 утра. Этот магазин закроется в 20.00, потому что он находится в подузле h hm = 13.00, в подузле h hm = 16.30 и в подузле h hm = 20.00. Итак, я должен получить это 20.00.

Случай 2: сейчас 12.40, и я должен знать, когда закроется 763. Он закроется в 16.30, независимо от того, включен ли он в последний узел (h hm = 22.00). Итак, я должен получить это 16.30.

Возможно ли это?

Заранее спасибо.

Ответы [ 4 ]

2 голосов
/ 14 февраля 2009

Вот как можно построить такое выражение XPatch:

Следующее выражение XPath выбирает желаемый результат

($vOpen[not(count(following-sibling::h[1] | $vOpen) 
          = 
           count($vOpen))
       ][1]/@hm
|

  $vOpen[last()]/@hm

 )

  [1]

где $vOpen

определяется как:

$vge1240[store/@id=$vId]

и $vge1240 определяется как:

/*/*/h[translate(@hm,':','') >= 1240]

и $vId определяется как:

1045

или

763

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

   (/*/*/h[translate(@hm,':','') >= 1240][store/@id=763]
      [not(count(following-sibling::h[1]
                |             
                 /*/*/h[translate(@hm,':','') >= 1240][store/@id=763]
                 )     
          =       
           count(/*/*/h[translate(@hm,':','') >= 1240][store/@id=763])) 
          ]  
          [1]
            /@hm


     |
        /*/*/h[translate(@hm,':','') >= 1240][store/@id=763]
           [last()]
                   /@hm 
       )

        [1]

Объяснение

($vOpen[not(count(following-sibling::h[1] | $vOpen) 
          = 
           count($vOpen))
       ][1]/@hm
|

  $vOpen[last()]/@hm

 )

  [1]

означает следующее:

  1. Из всех записей в «открытые» часы, которые содержат идентификатор (763)

  2. Возьмите тех, чей ближайший родственник не принадлежит этому набору (закрыт или не содержит 763)

  3. Из них возьмите первый.

  4. Возьмите первый (в порядке документа) из узла, выбранного на шаге 3 выше, и последний элемент в $vOpen. Это выберет последнюю запись в «открытых» часах, если все записи в ней содержат заданный идентификатор.

Здесь мы в основном используем метод Кейса для пересечения двух наборов узлов $ ns1 и $ ns2:

$ ns1 [count (. | $ Ns2) = count ($ ns2)]

1 голос
/ 13 февраля 2009

Я просто повторю последнюю часть моего ответа вам в последнем вопросе , на который вы ссылаетесь.

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

0 голосов
/ 14 февраля 2009

Я думаю, что это работает. Он находит последнее последовательное вхождение (после времени запуска) store / @ id, где @id = $ id, что, как я полагаю, вы искали.

<xsl:variable name="id" select="'1045'"/>
<xsl:variable name="st" select="translate('12:40',':','')"/>

...

((//h[translate(@hm,':','') >= $st])[position() = count(preceding-sibling::*[store/@id=$id])+1 and store/@id=$id])[last()]/@hm

Пояснение: Сначала выберите все элементы, которые имеют время начала> = до указанного начала. Затем в этих результатах выберите атрибут @hm последнего элемента, позиция которого равна числу предыдущих элементов, в которых есть запрошенный тег store / @ id.

Единственное ограничение в этой короткой версии состоит в том, что она не будет работать, если идентификатор хранилища не появится в первом элементе после времени запуска. Нижеследующее исправляет это ограничение, начиная с первого после времени запуска, которое содержит надлежащий store / @ id, но это немного запутанно:

<xsl:variable name="id" select="'1045'"/>
<xsl:variable name="st" select="translate('12:40',':','')"/>

...

((//h[translate(@hm,':','') >= $st and position() >= count(//h[not(preceding-sibling::*[store/@id=$id])])])[position() = count(preceding-sibling::*[store/@id=$id])+1 and store/@id=$id])[last()]/@hm
0 голосов
/ 13 февраля 2009

Если искомый идентификатор магазина находится в $store, он получит последний h/@hm, который содержит этот идентификатор, и сопровождается h, который не содержит его или последний h/@hm, который содержит этот идентификатор магазина (для магазинов, которые закрываются в последний h/@hm).

//h[not(store/@id=$store)]/preceding-sibling::h[store/@id = $store][1]/@hm | //h[store/@id=$store][last()]/@hm

Для тестирования в XSLT с вашим примером XML:

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:variable name="store" select="763"/>

    <xsl:template match="/">
        <closes>
            <xsl:value-of select="//h[not(store/@id=$store)]/preceding-sibling::h[store/@id = $store][1]/@hm | //h[store/@id=$store][last()]/@hm"/>
        </closes>
    </xsl:template>
</xsl:stylesheet>

Отпечатки <closes>16:30</closes>. Если вы измените $store на 1052, вместо этого будет напечатано <closes>22:00</closes>.

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