2009-02-13 6 views
1

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

<?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, потому что он находится в hnm = 13.00 subnode, в h hm = 16.30 subnode и в h hm = 20.00 subnode. Итак, я должен получить это 20.00.

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

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

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

+0

Уважаемые все, я сделал несколько последовательных изменений. Теперь решение является правильным и готовым к просмотру. Удачи :) –

+0

@vyger Да, вы были правы, и я исправил эту последнюю недостающую часть в своем ответе. Спасибо –

+0

@vyger Выражение XPath в моем ответе - это решение вашей второй проблемы (оно также решает первую проблему, и это не недостаток :)) –

ответ

2

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

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

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

    $vOpen[last()]/@hm 

) 

    [1] 

где $vOpen

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

$vge1240[store/@id=$vId] 

и $vge1240 d efined как:

/*/*/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. Из всех записей в часы "Open", которые содержат идентификатор (763)

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

  3. От первого принять.

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

Здесь мы используем в основном метод Kayesian для пересечения двух nodesets $ Ns1 и $ NS2:

$ ns1 [COUNT (|. $ NS2) = COUNT ($ NS2)]

+0

Привет, Dimitre, только примечание: дизайн двух запросов, который я объяснил в первом сообщении, должен быть сохранен. Мне нужен только второй запрос. – 2009-02-15 19:31:54

+0

@vyger Выражение XPath в моем ответе - это решение вашей второй проблемы (оно также решает первую проблему, и это не недостаток :)) –

+0

Вы имеете в виду ** Байесовский метод? – mousio

1

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

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

+0

не мог согласиться больше – Nathan

+0

Я бы добавил +1, но у меня кончились голоса – annakata

+0

@AnthonyWJones: есть причины не делать то, что вы предлагаете. Это то, что вы предлагаете - это последняя возможная вещь, которую я могу сделать. Я не говорю, что это не самое лучшее, но лучшее, что лучше для проекта, над которым вы работаете. – 2009-02-14 09:07:06

0

Если магазин ID вы ищете в $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>.

+0

Спасибо, что нашли время для ответа. Один вопрос (отсюда я не могу проверить, я должен подождать понедельник): что, если 763 находится в последнем узле (так что за ним ничего не следует)? – 2009-02-14 11:00:51

+0

* скрипка *, * скрипка * Конечно, делаю, правильно! ;-) –

0

Я думаю, что это работает. Он находит последнее последовательное появление (после времени начала) 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.

Единственным ограничением в этой короткой версии является то, что он не сработает, если идентификатор магазина не встречается в первом элементе после времени начала. Один ниже исправляет это ограничение, начиная с первым после времени начала, который содержит правильный магазин/@ идентификатор, но это немного хаотичное:

<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