Roxi

Vedi tutte le pagine e le modifiche recenti o scarica i sorgenti nella pagina


Descrizione

ROXI è stata inizialmente sviluppata da Gabriele Lana per l’implementazione di un wiki strutturato, ora è stata resa disponibile (con licenza LGPL) come libreria indipendente per la manipolazione di documenti XML

Parti Sviluppate

La metodologia di sviluppo utilizzata è eXtreme Programming, tutto il codice è stato sviluppato in Test Driven Development, questo ha fatto in modo che attualmente ci siano più di 400 test automatici per la verifica della correttezza del codice finora sviluppato

Parti Da Sviluppare

Altro

Esempi



# creazione di un elemento
XElement.new('node')

# creazione di un elemento contenente del testo
XElement.new('node', XText.new('text'))

# i metodi di manipolazione del dom sono abbastanza "smart" da
# riconoscere i tipi di dati passati come parametri attuali e quindi
# comportarsi di conseguenza
XElement.new('node', 'text')

# creazione di un documento un po' piu' complesso
XDocument.new(
  XElement.new('root',
    XAttribute.new('attribute_1', 'value'),
    XAttribute.new('attribute_2', 'value'),
    XInstruction.new('php', 'phpinfo();')
    XElement.new('child',
      XNamespace.new('prefix', '/some/url'),
      XAttribute.new('attribute', 'value'),
      XElement.new('child',
        XAttribute.new('attribute', 'value')
        XElement.new('child',
          XComment.new('some comment'),
        )
      )
    ),
    XText.new('some text'),
  )
)

# esempi di utilizzo di XPath

# il codice seguente calcola il prezzo totale di un ordine
total = XDocument.open(@order) do | doc |
  doc.xpath('//item').inject(0) do | total, item |
    price = item.child('price').to_n
    quantity = item.child('quantity').to_n
    total += price * quantity
  end
end

# in maniera piu' compatta, sfruttando di piu' xpath
total = XDocument.open(@order) do | doc |
  doc.xpath('//item').inject(0) do | total, item |
    total += item.xpath('price * quantity')
  end
end

# ancora piu' compatto, sfruttando delle estensioni non standard (mul)
total = XDocument.open(@order).xpath('sum(mul(//item/price, //item/quantity))')

# esempi di utilizzo di XUpdate (esempio originale e relativa traduzione)

# <xupdate:modifications version="1.0" xmlns:xupdate="http://www.xmldb.org/xupdate">
#   <xupdate:insert-before select="/addresses/address[@id = 1]/name/last" >   
#     <xupdate:element name="middle">Lennox</xupdate:element>      
#   </xupdate:insert-before>
# </xupdate:modifications>

doc = XDocument.string(@xml).update do
  select('/addresses/address[@id=1]/name/last') do | node |
    node.insert_before(XElement.new('middle', 'Lennox'))
  end
end

# <xupdate:modifications version="1.0" xmlns:xupdate="http://www.xmldb.org/xupdate">
#   <xupdate:variable name="state" select="/addresses/address[@id = 1]/state"/>
#   <xupdate:insert-after select="/addresses/address[@id = 1]/country">
#     <xupdate:value-of select="$state"/>
#   </xupdate:insert-after>
# </xupdate:modifications>

doc = XDocument.string(@xml).update do
  select('/addresses/address[@id=1]') do | node |
    node.child('country').insert_after(node.child('state').clone)
  end
end

# <xupdate:modifications version="1.0" xmlns:xupdate="http://www.xmldb.org/xupdate">
#   <xupdate:remove select="/addresses/address[@id = 1]/phone"/>
# </xupdate:modifications> 

doc = XDocument.string(@xml).update do
  remove('/addresses/address[@id=1]/phone')
end

# alcuni esempi di utilizzo di XQuery (esempio originale e traduzione)

# <ul> {
#   for $x in doc("books.xml")/bookstore/book/title
#   order by $x
#   return <li>{$x}</li>
# }
# </ul>

element = XElement.new('ul',
  XQuery.from(XDocument.open(@books).xpath('/bookstore/book/title')) do
          order_by { | title | title.value }
          select { | title | XElement.new('li', title) }
  end
)

# supporto anche delle features non standard come la group_by (anche
# se un po' macchinosa), e la filter dove e' possibile manipolare
# tutto il result set attuale, in questo caso viene utilizzato per
# limitare il numero di risultati

XQuery.from(nodeset) do
  order_by(:descending) { | selection |
    selection.attribute('take').to_f
  }
  filter { | selections |
    selections[1..15]
  }
  select { | selection |
        puts selection.attribute('take').value
  }
end

# in piu' con opportune estensioni di xpath (in questo caso le
# funzioni distinct-values e min) si riescono ad eseguire query
# di questo tipo

# <results>
#   {
#     let $doc := doc("prices.xml")
#     for $t in distinct-values($doc//book/title)
#     let $p := $doc//book[title = $t]/price
#     return
#       <minprice title="{ $t }">
#         <price>{ min($p) }</price>
#       </minprice>
#   }
# </results> 

doc = XDocument.open(@prices)
  XElement.new('result',
    XQuery.from(doc.xpath('distinct-values(//book/title)')) do
      select do | title |
        minprice = doc.xpath("min(//book[title = '#{title}']/price)")
        XElement.new('minprice',
          XAttribute.new('title', title),
          XElement.new('price', minprice)
        )
      end
    end
  )
)

# esempio di Binding

# Definiamo per ogni attributo della classe News
# l'espressione XPath che una volta valutata costituirà
# il valore dell'attributo stesso

class News
  extend XBind
  xattribute :title => 'only(strings(*[@class = "title"]))'
  xattribute :insert_date => 'only(dates(*[@class = "insert_date"]))'
  xattribute :expire_date => 'only(dates(*[@class = "expire_date"]))'
  xattribute :text => 'normalize-space(only(strings(*[@class = "text"])))'
end

# supponiamo di avere un xml di questo tipo

# <html>
#   <head>
#     <title>XPUG NEWS</title>
#   </head>
#   <body>
#     <div class="news">
#       <span class="title">First News</span>
#       <span class="insert_date">20060404</span>
#       <span class="expire_date">20060414</span>
#       <div class="text">
#         First News Text
#       </div>
#     </div>
#     <div class="news">
#       <span class="title">Second News</span>
#       <span class="insert_date">20060403</span>
#       <span class="expire_date">20060413</span>
#       <div class="text">
#         Second News Text
#       </div>
#     </div>
#     <div class="news">
#       <span class="title">Third News</span>
#       <span class="insert_date">20060402</span>
#       <span class="expire_date">20060412</span>
#       <div class="text">
#         Third News Text
#       </div>
#     </div>
#   </body>
# </html>

# per ogni news presente nella pagina eseguiamo dei test

today = Date.today
XDocument.open('<file>.html').xpath('//*[@class = "news"]').each do | news_dom |
  news = News.new(news_dom)
  assert today <= news.expire_date, "'#{news.title}' should be expired at #{today}" 
end

# news = News.new(news_dom)
# istanzia News
# valorizza gli attributi dell'oggetto valutando le espressioni xpath su news_dom
# crea i metodi di accesso agli attributi


Updated on April 19, 2006 00:25 by Ruby Fan (81.208.60.192)