Сравнение двух атрибутов на разных уровнях иерархии с использованием XPath в C # .NET 3.5 - PullRequest
4 голосов
/ 06 октября 2011

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

<A>
  <B>
     <C Since="2011-09-26T11:12:41.1383089Z">
       <E Name="One" AnotherDate="2011-09-26T10:54:05.7025781Z"/>
       <E Name="Two" AnotherDate="2011-09-26T11:54:05.7025781Z"/>
     </C>
  </B>
</A>

Мое выражение Xpath выглядит следующим образом:

//A/B/C/E[@AnotherDate <= ../@Since]

Это прекрасно работает с XMLSpy, также в запросе T-SQL 2008

where X.exists(xpathexpression)=1 

, но не в .NET 3.5 с XmlDocument.SelectNodes ().

Насколько я понимаю, в документации по xpath этот запрос должен быть возможен в XPATH 1.0, который .NET поддерживает в этой версии.

Чего я пытаюсь достичь: Я хочу выбрать все элементы E , которые имеют AnotherDate ранее или равны их родительскому элементу C С атрибутом .

Итак: что я делаю не так или что я могу изменить, чтобы добиться чего-то подобного. Обратите внимание, что запрос также должен работать в данном предложении sql where.

Ответы [ 2 ]

1 голос
/ 07 октября 2011

Это довольно просто. Используйте

  /A/B/C/E
     [not(translate(@AnotherDate, '-:TZ', '')
         >
          translate(../@Since, '-:TZ', '')
          )
      ]

Проверка на основе XSLT :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>

 <xsl:template match="/">
     <xsl:copy-of select=
     "/A/B/C/E
         [not(translate(@AnotherDate, '-:TZ', '')
             >
              translate(../@Since, '-:TZ', '')
              )
          ]
     "/>
 </xsl:template>
</xsl:stylesheet>

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

<A>
    <B>
        <C Since="2011-09-26T11:12:41.1383089Z">
            <E Name="One" AnotherDate="2011-09-26T10:54:05.7025781Z"/>
            <E Name="Two" AnotherDate="2011-09-26T11:54:05.7025781Z"/>
        </C>
    </B>
</A>

требуемый, правильный результат (выбран только один узел) копируется в вывод :

<E Name="One" AnotherDate="2011-09-26T10:54:05.7025781Z" />

Объяснение : Использование стандартной функции XPath 1.0 translate() для удаления всех нецифровых символов из значений даты и времени, так что Остальные строки, состоящие только из цифр, можно затем корректно сравнивать как числа.

0 голосов
/ 06 октября 2011

Мне кажется, это ведет себя согласно спецификации :

Когда ни один объект для сравнения не является набором узлов, а оператор <=, <,> = или>, тогда объекты сравниваются путем преобразования обоих объектов в числа и сравнения чисел в соответствии с IEEE 754.

И преобразование строк в числа:

строка, состоящая из необязательного пробела, за которым следует необязательный знак минуса, за которым следует число, за которым следует пробел, преобразуется в ближайший номер IEEE 754 (согласно правилу округления до ближайшего стандарта IEEE 754) в математическое значение представлены строкой; любая другая строка преобразуется в NaN

Итак, в вашем случае сравниваются два NaN, что возвращает false. Из-за этого ни один узел не возвращается. В XPath 2.0 поведение отличается, поэтому, вероятно, оно работает в других средах.

Я не думаю, что вы можете выбрать такие узлы, используя только XPath 1.0. Итак, я думаю, что вы не можете сделать это, просто используя один SelectNodes(). Если вы хотите достичь этого с помощью одного запроса XPath 1.0, вы должны обойти его ограничения. Смотрите ответ Димитра, как это сделать.

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