powered by simpleCommunicator - 2.0.55     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Cложный запрос XPath
25 сообщений из 30, страница 1 из 2
Cложный запрос XPath
    #38764946
rigorMortis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Привет

Подскажите, пожалуйста, можно ли выразить такой запрос на XPath. Есть xml:

Код: xml
1.
2.
3.
4.
<elementList>
 <element date="01.01.2014" time="3600">
 <element date="01.02.2014" time="600">
</elementList>



C date всё понятно, time - время от начала суток в виде количества секунд. Нужно выбрать XmlNode где element содержит самую последнюю дату включая время суток. Или придётся выбирать все узлы и делать выборку в цикле?
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765027
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Честно говоря, не знаю, но возможно поможет.

Сначала нужно отсортировать ваши элементы, например: http://www.sql.ru/forum/1106056/sortirovka-elementov-xml. То есть XQuery, а не XPath

А дальше, просто взять последний (первый) элемент в списке.

А с чем связано ограничение на XPath?
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765052
rigorMortis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79, не, XQuery это же БД. А мне в C# надо. На уровне БД выбрать не получится.
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765065
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rigorMortisArm79, не, XQuery это же БД. А мне в C# надо. На уровне БД выбрать не получится.
Да? а эти: XQSharp and Saxon?

C другой стороны, чем плох LINQ-to-XML? Зачем вам извращаться с XPath?
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765080
rigorMortis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79, Ну, вообще не обязательно XPath. Вопрос в том чтобы сделать более рационально чем писать метод для разбора даты элемента. А на LINQ-to-XML как сделать?
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765102
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rigorMortisArm79, Ну, вообще не обязательно XPath. Вопрос в том чтобы сделать более рационально чем писать метод для разбора даты элемента. А на LINQ-to-XML как сделать?

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
    class Program
    {
        static void Main(string[] args)
        {
            var xDoc = XDocument.Parse(@"
                <elementList>
                    <element date=""01.01.2014"" time=""3600"" />
                    <element date=""01.03.2014"" time=""7600"" />
                    <element date=""01.03.2014"" time=""600"" />
                    <element date=""01.02.2014"" time=""3600"" />
                </elementList>
            ");

            var element = xDoc.Root
                .Elements("element")
                .OrderBy(xe => DateTime.ParseExact(xe.Attribute("date").Value, "dd.MM.yyyy", CultureInfo.InvariantCulture).AddSeconds(int.Parse(xe.Attribute("time").Value)))
                .Last();

            Console.WriteLine(element);
            Console.ReadKey();
        }
    }



Вывод:
<element date="01.03.2014" time="7600" />
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765105
Ilya81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rigorMortisА на LINQ-to-XML как сделать?
Примерно так (не проверял):
Код: c#
1.
2.
XElement mainElement = XElement.Parse(/*  Ваш XML*/);
XElement lastDateElement = mainElement.Elements(XName.Get("element"))..OrderByDescending(el => DateTime.Parse(el.Attribute(XName.Get("date")).Value) + TimeSpan.Parse(el.Attribute(XName.Get("time")).Value)).First();
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765107
rigorMortis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Надо попробовать...
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765111
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rigorMortisПодскажите, пожалуйста, можно ли выразить такой запрос на XPath
Нельзя. Потому что нужно преобразование строк в даты, а XPath/XSLT версии 1.0 этого не умеют (а дотнетовские парсер/процессор работает именно с 1.0). Конечно, можно было бы порекомендовать Saxon HE (например), но и это бы не спасло - даты не в формате xs:date, и преобразование к типу xs:date выдаст ошибку. Хотя, остается еще вариант констрирования правильного формата через substring - но потом возникнут проблемы с нахождением максимума от двух аргуметов. Я бы сделал так:
1) тождественное пребразование с добавлением атрибута, содержащего дату+время в формате unix epoch:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:output method="xml" />
  <xsl:template match="*">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <xsl:if test="self::element">
        <xsl:attribute name="dt">
          <xsl:value-of select="(
            xs:dateTime(
              xs:date(
                concat(
                  substring(@date,7),'-',
                  substring(@date, 4, 2), '-',
                  substring(@date, 1, 2)
                )
              )
            )+xs:dayTimeDuration(concat('PT',@time,'S')
          ) - xs:dateTime('1970-01-01T00:00:00')) div xs:dayTimeDuration('PT1S')" />
        </xsl:attribute>
      </xsl:if>
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>


получим
Код: xml
1.
2.
3.
4.
<elementList>
  <element date="01.01.2014" time="3600" dt="1388538000" />
  <element date="01.02.2014" time="600" dt="1391213400" />
</elementList>

и дальше всё совсем просто:
Код: xml
1.
/elementList/element[@dt=max(//@dt)]


Но, повторюсь, это XPath/XSLT 2.0, если пользоваться можно только средствами фреймворка - проще распарсить и определить нужный тэг в коде.
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765112
codearticles.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
string xml = "<elementList><element date=\"01.01.2014\" time=\"3600\" /><element date=\"01.02.2014\" time=\"600\" /></elementList>";
            
var items = XElement.Parse(xml).Elements().Select(x => 
    new { date = XmlConvert.ToDateTime(x.Attribute("date").Value, "dd.MM.yyyy"), time = Convert.ToInt32(x.Attribute("time").Value) });
            
var item = (from i in items                       
            let max = items.Max(x => x.date)
            where i.date == max
            select i).FirstOrDefault();
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765116
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
codearticles.ru
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
string xml = "<elementList><element date=\"01.01.2014\" time=\"3600\" /><element date=\"01.02.2014\" time=\"600\" /></elementList>";
            
var items = XElement.Parse(xml).Elements().Select(x => 
    new { date = XmlConvert.ToDateTime(x.Attribute("date").Value, "dd.MM.yyyy"), time = Convert.ToInt32(x.Attribute("time").Value) });
            
var item = (from i in items                       
            let max = items.Max(x => x.date)
            where i.date == max
            select i).FirstOrDefault();



МСУ, а куда ты дел time?
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765118
codearticles.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79МСУ, а куда ты дел time?
Упс, виноват, 79 :)

Код: c#
1.
2.
3.
4.
var item = (from i in items                       
            let max = items.Max(x => x.date.AddSeconds(x.time))
            where i.date.AddSeconds(i.time) == max
            select i).FirstOrDefault();
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765123
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
codearticles.ruArm79МСУ, а куда ты дел time?
Упс, виноват, 79 :)

Код: c#
1.
2.
3.
4.
var item = (from i in items                       
            let max = items.Max(x => x.date.AddSeconds(x.time))
            where i.date.AddSeconds(i.time) == max
            select i).FirstOrDefault();



Эх, любишь ты все усложнять. AddSeconds сразу же бы сделал, и обошелся бы прекрасно без ерунды типа let max. Зачем дважды что-то прибавлять.
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765130
codearticles.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79Эх, любишь ты все усложнять. AddSeconds сразу же бы сделал, и обошелся бы прекрасно без ерунды типа let max. Зачем дважды что-то прибавлять.
Вся прелесть let в том, что оно вычисляется один раз и хранится в переменной диапазона. И может сколько угодно использоваться в запросе. Незаменимая штука в группировках-агрегатах. Жалко, что в лямбде нету такой фишки. Кстати, let будет оптимальнее, чем формирование сортировки типа OrderBy + Last.
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765136
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
codearticles.ruArm79Эх, любишь ты все усложнять. AddSeconds сразу же бы сделал, и обошелся бы прекрасно без ерунды типа let max. Зачем дважды что-то прибавлять.
Вся прелесть let в том, что оно вычисляется один раз и хранится в переменной диапазона. И может сколько угодно использоваться в запросе. Незаменимая штука в группировках-агрегатах. Жалко, что в лямбде нету такой фишки. Кстати, let будет оптимальнее, чем формирование сортировки типа OrderBy + Last.
Может быть. Но тут уже вопрос компромисса - понятный код, хоть и работающий чуточку медленнее, или более быстрая, но некрасиво выглядящая конструкция? :-)
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765139
codearticles.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79,
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765142
Ilya81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
codearticles.ruArm79Эх, любишь ты все усложнять. AddSeconds сразу же бы сделал, и обошелся бы прекрасно без ерунды типа let max. Зачем дважды что-то прибавлять.
Вся прелесть let в том, что оно вычисляется один раз и хранится в переменной диапазона. И может сколько угодно использоваться в запросе. Незаменимая штука в группировках-агрегатах. Жалко, что в лямбде нету такой фишки. Кстати, let будет оптимальнее, чем формирование сортировки типа OrderBy + Last.
OrderBy + Last - возможно, а вот OrderByDescending + First - другое дело, ибо LINQ использует отложенное исполнение и запрос выполняется полностью, значит, первая итерация сортировки OrderByDescending находит первый элемент и функции First его достаточно, дальше сортировка выполняться не будет. Но при этом один проход, так что, думаю, это оптимальный вариант.
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765150
rigorMortis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
            XmlNode result = null;
            long ticks = 0;

            foreach (XmlNode node in List)//здесь список elements
            {
                long currentTicks = 0;

                currentTicks = DateTime.Parse(node .Attributes["Date"].Value).Ticks;
                currentTicks += TimeSpan.FromSeconds(int.Parse(node .Attributes["Time"].Value)).Ticks;

                if (currentTicks > ticks)
                {
                    ticks = currentTicks;
                    result = node ;
                }

            return node;
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765169
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
codearticles.ruКстати, let будет оптимальнее, чем формирование сортировки типа OrderBy + Last.

Вот раздразнил меня:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
            var xDoc = XDocument.Parse(@"
                <elementList>
                    <element date=""01.01.2014"" time=""3600"" />
                    <element date=""01.03.2014"" time=""7600"" />
                    <element date=""01.03.2014"" time=""600"" />
                    <element date=""01.02.2014"" time=""3600"" />
                </elementList>
            ");

            var items = xDoc.Root.Elements("element");
            var items2 = items.Select(x => new { date = XmlConvert.ToDateTime(x.Attribute("date").Value, "dd.MM.yyyy"), time = Convert.ToInt32(x.Attribute("time").Value) });

            var sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < 100000; i++)
            {
                var element = items
                    .OrderBy(xe => DateTime.ParseExact(xe.Attribute("date").Value, "dd.MM.yyyy", CultureInfo.InvariantCulture).AddSeconds(int.Parse(xe.Attribute("time").Value)))
                    .Last();
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);

            
            sw.Reset();
            sw.Start();
            for (int j = 0; j < 100000; j++)
            {
                var item = (from i in items2
                            let max = items2.Max(x => x.date.AddSeconds(x.time))
                            where i.date.AddSeconds(i.time) == max
                            select i).FirstOrDefault();
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);



Вывод:
327
833
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765173
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ilya81OrderBy + Last - возможно, а вот OrderByDescending + First - другое дело
Один фиг. Только что проверил.
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765441
codearticles.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79Вывод:
327
833
Ну, батенька, вам надо бы матчасть закрепить в области отложенных вычислений :)

Код: c#
1.
var items2 = items.Select(x => new { date = XmlConvert.ToDateTime(x.Attribute("date").Value, "dd.MM.yyyy"), time = Convert.ToInt32(x.Attribute("time").Value) }).ToList();



Вывод:
301
125
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765562
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
codearticles.ruArm79Вывод:
327
833
Ну, батенька, вам надо бы матчасть закрепить в области отложенных вычислений :)

Код: c#
1.
var items2 = items.Select(x => new { date = XmlConvert.ToDateTime(x.Attribute("date").Value, "dd.MM.yyyy"), time = Convert.ToInt32(x.Attribute("time").Value) }).ToList();




Вывод:
301
125
ну, МСУ, при прочих равных...

тогда уж и здесь к списку приведите
var items = xDoc.Root.Elements("element");
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765595
codearticles.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79тогда уж и здесь к списку приведите
Код: c#
1.
var items = xDoc.Root.Elements("element");


Ничего не поменяется.
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765622
codearticles.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79, а вообще, если на то пошло, у тебя кривой тест. Тест с OrderBy + Last уже априори будет проигрывать по причине, потому что в нем есть конвертации времени и числа. Вот правильный тест.

test let vs order
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
string xml = "<elementList><element date=\"01.01.2014\" time=\"3600\" /><element date=\"01.02.2014\" time=\"600\" /></elementList>";

var items = XElement.Parse(xml).Elements().Select(x =>
    new { date = XmlConvert.ToDateTime(x.Attribute("date").Value, "dd.MM.yyyy"), time = Convert.ToInt32(x.Attribute("time").Value) }).ToList();

            
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 100000; i++)
{
    var item = items.OrderBy(x => x.date.AddSeconds(x.time)).LastOrDefault();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

sw.Reset();
sw.Start();

var max = items.Max(x => x.date.AddSeconds(x.time));
for (int j = 0; j < 100000; j++)
{
    var item = items.Where(x => x.date.AddSeconds(x.time) == max).FirstOrDefault();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);



Вывод: 39, 24

P.S. Готовится единая коллекция в памяти и только потом по ней идут замеры. В целях оптимизации let был вынесен в отдельную переменную max. Те же яйца, только оптимальнее
...
Рейтинг: 0 / 0
Cложный запрос XPath
    #38765649
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
codearticles.ru,

Не согласен :-) Себе то ты заранее готовишь новый список:
codearticles.ru
Код: c#
1.
2.
var items = XElement.Parse(xml).Elements().Select(x =>
    new { date = XmlConvert.ToDateTime(x.Attribute("date").Value, "dd.MM.yyyy"), time = Convert.ToInt32(x.Attribute("time").Value) }).ToList();



А мне почему то вычисления в цикл пихаешь:
codearticles.ru
Код: c#
1.
items.OrderBy(x => x.date.AddSeconds(x.time)).LastOrDefault();



Ты у меня тоже новый список с предрассчитанными данными сделай, а потом только тесть :-)
...
Рейтинг: 0 / 0
25 сообщений из 30, страница 1 из 2
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Cложный запрос XPath
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]