Каков синтаксис xpath для получения 1-го, 2-го и 3-го вхождения элемента в другой элемент

У меня есть следующий XML-документ (я удалил ненужные данные):

<?xml version="1.0"?>
<NewOrderNotification xmlns="http://payments.amazon.com/checkout/2008-11-30/">
  <ProcessedOrder>
    <ShippingServiceLevel>blah</ShippingServiceLevel>
    <ProcessedOrderItems>
      <ProcessedOrderItem>
        <AmazonOrderItemCode>blah</AmazonOrderItemCode>
        <Price>
          <Amount>0.2</Amount>
          <CurrencyCode>GBP</CurrencyCode>
        </Price>
        <ItemCharges>
          <Component>
            <Type>Principal</Type>
            <Charge>
              <Amount>0.2</Amount>
              <CurrencyCode>GBP</CurrencyCode>
            </Charge>
          </Component>
          <Component>
            <Type>Shipping</Type>
            <Charge>
              <Amount>0.95</Amount>
              <CurrencyCode>GBP</CurrencyCode>
            </Charge>
          </Component>
          <Component>
            <Type>PrincipalPromo</Type>
            <Charge>
              <Amount>0.0</Amount>
              <CurrencyCode>GBP</CurrencyCode>
            </Charge>
          </Component>
          <Component>
            <Type>ShippingPromo</Type>
            <Charge>
              <Amount>0.0</Amount>
              <CurrencyCode>GBP</CurrencyCode>
            </Charge>
          </Component>
        </ItemCharges>
        <ShippingCustomData>null</ShippingCustomData>
      </ProcessedOrderItem>
    </ProcessedOrderItems>
  </ProcessedOrder>
</NewOrderNotification>

Я хочу знать синтаксис xpath для получения каждого из значений в 5 различных элементах <Amount>:

А именно, как мне извлечь каждое из следующего:

  • NewOrderNotification - ProcessedOrder - ProcessedOrderItems - ProcessedOrderItem - Цена - Сумма

  • NewOrderNotification — ProcessedOrder — ProcessedOrderItems — ProcessedOrderItem — ItemCharges — Component (с типом = принцип) — Charge — Amount

  • NewOrderNotification — ProcessedOrder — ProcessedOrderItems — ProcessedOrderItem — ItemCharges — Component (с типом = доставка) — Charge — Amount

  • NewOrderNotification — ProcessedOrder — ProcessedOrderItems — ProcessedOrderItem — ItemCharges — Component (с типом = PrincipalPromo) — Charge — Amount

  • NewOrderNotification - ProcessedOrder - ProcessedOrderItems - ProcessedOrderItem - ItemCharges - Component (с type=ShippingPromo) - Charge - Amount

Обратите внимание на xmlns в корневом элементе.

Это код JScript, который я использую для извлечения элементов:

var xmlDoc = Server.CreateObject("Msxml2.DOMDocument.6.0");
xmlDoc.setProperty("SelectionNamespaces", "xmlns:a='http://payments.amazon.com/checkout/2008-11-30/'");
xmlDoc.loadXML(xml);
var node = xmlDoc.documentElement.selectSingleNode("XPATH_IN_HERE");
return node.text;

person Graham    schedule 05.11.2012    source источник


Ответы (3)


Первую сумму вы можете получить всего лишь:

//Price/Amount/text()
#=> "0.2"

Для остальных четырех вы можете использовать текст предыдущего родственного элемента Type, чтобы получить их значения:

//Charge[preceding-sibling::Type="Principal"]/Amount/text()
#=> "0.2"

//Charge[preceding-sibling::Type="Shipping"]/Amount/text()
#=> "0.95"

//Charge[preceding-sibling::Type="PrincipalPromo"]/Amount/text()
#=> "0.0"

//Charge[preceding-sibling::Type="ShippingPromo"]/Amount/text()
#=> "0.0"

Я думаю, что это делает это. (Сообщите мне, если я неправильно понял ваш вопрос.)

person Chris Salzberg    schedule 05.11.2012
comment
Я отредактировал свой вопрос, включив в него фрагмент кода, который я использую. Возможно, это мой код, но я не могу заставить работать первый из них. Я пока не пробовал другие. Я также пробовал //a:NewOrderNotification/ProcessedOrder/ProcessedOrderItems/ProcessedOrderItem/Price/Amount без успеха - person Graham; 05.11.2012
comment
Это может помочь - я удалил xmlns из xml и удалил строку setProperty из своего кода, тогда ваш ответ работает. Итак, какая модификация xpath мне понадобится для работы с xmlns? - person Graham; 05.11.2012
comment
Извините, я использую ruby/Nokogiri, поэтому сравнивать немного сложно, но я также обнаружил, что это работает после удаления пространства имен. С пространством имен в nokogiri вы должны добавлять xmnls: к каждому тегу, например: //xmlns:Charge[preceding-sibling::xmlns:Type="ShippingPromo"]/xmlns:Amount/text() и т. д. - person Chris Salzberg; 05.11.2012
comment
p.p.s. что такое a в xmlns:a? а что если просто сделать: xmlDoc.setProperty("SelectionNamespaces", "xmlns='http://payments.amazon.com/checkout/2008-11-30/'"); - person Chris Salzberg; 05.11.2012
comment
не нравится без a - я считаю, что a - это просто псевдоним для длинного пространства имен. Пробовал //xmlns:Charge[preceding-sibling::xmlns:Type=ShippingPromo]/xmlns:Amount/text‌​() и все еще не работает, но я думаю, что мы приближаемся - person Graham; 05.11.2012
comment
Ах, бинго - в конце концов получилось: //a:Charge[preceding-sibling::a:Type=\Principal\]/a:Amount Спасибо за помощь - person Graham; 05.11.2012

Или, если вам нравятся сокращенные абсолютные пути

'/NewOrderNotification/ProcessedOrder/ProcessedOrderItems/ProcessedOrderItem/ItemCharges/Component[Type="Shipping"]/Charge/Amount/text()'
person Himanshu    schedule 05.11.2012

Я поместил свои быстрые и грязные xpaths в следующий скрипт xslt.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:test="http://payments.amazon.com/checkout/2008-11-30/">
    <xsl:output indent="yes"/>

    <!-- Standard if you can define namespaces -->
    <xsl:variable name="amount1" select="//test:Price/test:Amount"/>
    <!-- for cases with namespace problems -->
    <xsl:variable name="amount2" select="//*[local-name() = 'Component'][1]/*[local-name() = 'Charge']/*[local-name() = 'Amount']"/>
    <!-- you can add the other in the same way -->


    <xsl:template match="/">
        <test>
        <variable1><xsl:value-of select="$amount1"/></variable1>    
        <variable2><xsl:value-of select="$amount2"/></variable2>
        </test> 
    </xsl:template>
</xsl:stylesheet>
person OkieOth    schedule 05.11.2012
comment
@Graham В unix-подобных системах вы можете вызвать ... xsltproc myXSLTStylesheet.xsl yourXMLFile.xml Где вы хотите использовать xpath? - person OkieOth; 05.11.2012
comment
Я использую его в классическом ASP (JScript), поэтому unix мне не подходит. - person Graham; 05.11.2012
comment
скопируйте xpaths из количества переменных * ... второй более независим от пространства имен - person OkieOth; 05.11.2012