Вопрос об обновлении XQuery

#xml #xslt #xquery

#xml #xslt #xquery

Вопрос:

Вот мой xml

 <book asin="0201100886"
  created="128135928"
  lastLookupTime="128135928">
  <price>102.00</price>
  <purchaseDate>2005-01-22</purchaseDate>
</book>

<book asin="0122513363" created="128135600" lastLookupTime="128136224">
  <price>50.95</price>
  <purchaseDate>2005-01-22</purchaseDate>
</book>

<book asin="0201441241"
  created="128136896"
  lastLookupTime="128136896">
  <price>108.20</price>
  <purchaseDate>2005-01-22</purchaseDate>
</book>


<book asin="0471250600"
  created="128136896"
  lastLookupTime="128136896">
  <price>107.95</price>
  <purchaseDate>2005-01-22</purchaseDate>
</book>

<book asin="0321193628"
  created="128136896"
  lastLookupTime="128136896">
  <price>112.40</price>
</book>
  

Мне нужно обновить цены на все книги на 0,50 цента. Как я могу это сделать?

Комментарии:

1. Обязательно ли это делать с помощью XQuery или вы можете использовать XSLT?

2. Хороший вопрос, 1. Смотрите мой ответ для рекомендации и полного, очень короткого решения XSLT 🙂

Ответ №1:

Если вы ищете решение, используя средство обновления XQuery:

 for $p in //price return
replace value of node $p with $p   0.50
  

Комментарии:

1. Изменит ли это мой существующий xml?

Ответ №2:

В XQuery для выполнения преобразования используется рекурсивная функция.

 declare function local:reprice($nodes as node()*) {
  for $node in $nodes
  return
    typeswitch($node)
       case element(price)
          return element price {xs:decimal($node)   0.5}
       case element(
          return 
            element {name($node)} {
               $node/@*,
               local:reprice($node/node())}
      default
        return $node
 };
  

тогда, если на документ books ссылаются как на $books:

 local:reprice($books)
  

Дальнейшее обсуждение и примеры в http://en.wikibooks.org/wiki/XQuery/Typeswitch_Transformations.

В качестве альтернативы используйте базу данных XML, такую как eXist-db, и обновите institu:

  for $price in $books//price
 let $newprice := xs:decimal($price)   0.5
 return update replace $price with elememt price {$newprice}
  

Обратите внимание, что расширения обновления XQuery в основном зависят от реализации, пока обновление XQuery не получит более широкой поддержки

Ответ №3:

XSLT значительно более подходит для использования, чем XQuery, для такого рода задач:

Это преобразование:

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


 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="price/text()">
  <xsl:value-of select="format-number(.   0.50, '##0.00')"/>
 </xsl:template>
</xsl:stylesheet>
  

при применении к предоставленному XML-документу:

 <books>
    <book asin="0201100886"   created="128135928"   lastLookupTime="128135928">
        <price>102.00</price>
        <purchaseDate>2005-01-22</purchaseDate>
    </book>
    <book asin="0122513363" created="128135600" lastLookupTime="128136224">
        <price>50.95</price>
        <purchaseDate>2005-01-22</purchaseDate>
    </book>
    <book asin="0201441241"   created="128136896"   lastLookupTime="128136896">
        <price>108.20</price>
        <purchaseDate>2005-01-22</purchaseDate>
    </book>
    <book asin="0471250600"   created="128136896"   lastLookupTime="128136896">
        <price>107.95</price>
        <purchaseDate>2005-01-22</purchaseDate>
    </book>
    <book asin="0321193628"   created="128136896"   lastLookupTime="128136896">
        <price>112.40</price>
    </book>
</books>
  

выдает желаемый, правильный результат:

 <books>
   <book asin="0201100886" created="128135928" lastLookupTime="128135928">
      <price>102.50</price>
      <purchaseDate>2005-01-22</purchaseDate>
   </book>
   <book asin="0122513363" created="128135600" lastLookupTime="128136224">
      <price>51.45</price>
      <purchaseDate>2005-01-22</purchaseDate>
   </book>
   <book asin="0201441241" created="128136896" lastLookupTime="128136896">
      <price>108.70</price>
      <purchaseDate>2005-01-22</purchaseDate>
   </book>
   <book asin="0471250600" created="128136896" lastLookupTime="128136896">
      <price>108.45</price>
      <purchaseDate>2005-01-22</purchaseDate>
   </book>
   <book asin="0321193628" created="128136896" lastLookupTime="128136896">
      <price>112.90</price>
   </book>
</books>
  

Комментарии:

1. Я должен использовать XQuery и изменить существующий xml. xslt довольно гладкий, и я хотел бы им воспользоваться : (

2. @zach: В XQuery есть что-то вроде typeswitch (никогда не имел несчастья использовать это) — прочитайте об этом и используйте. Это очень примитивный механизм сопоставления, который мог бы в некоторой степени помочь. w3.org/TR/xquery/#id-typeswitch