View Category
XML

Process an XML document

Given the XML Document:

<shopping>
  <item name="bread" quantity="3" price="2.50"/>
  <item name="milk" quantity="2" price="3.50"/>
</shopping>

Print out the total cost of the items, e.g. $14.50
ruby
#!/usr/bin/env ruby

# needed to parse xml
require 'rexml/document'

# grab the file
file = File.new('shop.xml')

# load it as an xml document
doc = REXML::Document.new(file)

# initialize the total to 0 as a float
total = 0.0

# cycle through the items
doc.elements.each('shopping/item') do |item|

# add the price to the total
total += item.attributes['price'].to_f
end

# round the total to the nearest 0.01
total = (total*100.0).round/100.0

# pad the output with the proper number of trailing 0's
printf "$%.2f\n", total
java
// solution uses JAXP and SAX included in Java API since version >= 1.5
class ShoppingContentHandler extends DefaultHandler {
Double priceSum = 0d;
@Override
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
if(name.equals("item")) {
String quantityString = attributes.getValue(attributes.getIndex("quantity"));
String priceString = attributes.getValue(attributes.getIndex("price"));
Integer quantity = Integer.parseInt(quantityString);
Double price = Double.parseDouble(priceString);
priceSum += (quantity * price);
}
}
public Double getPriceSum() {
return priceSum;
}
}

SAXParserFactory parserFactory = SAXParserFactory.newInstance();
try {
SAXParser parser = parserFactory.newSAXParser();
XMLReader reader = parser.getXMLReader();
ShoppingContentHandler contentHandler = new ShoppingContentHandler();
reader.setContentHandler(contentHandler);
reader.parse(new InputSource(new FileReader("shopping.xml")));
System.out.printf("$%.2f", contentHandler.getPriceSum());

} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
perl
#! /usr/bin/perl
# -*- Mode: CPerl -*-

use strict;
use XML::Simple;
use Data::Dumper;

# Given the XML Document:
#
# <shopping>
# <item name="bread" quantity="3" price="2.50"/>
# <item name="milk" quantity="2" price="3.50"/>
# </shopping>
#
# Print out the total cost of the items, e.g. $14.50

my $xml =
" <shopping>\n"
." <item name=\"bread\" quantity=\"3\" price=\"2.50\"/>\n"
." <item name=\"milk\" quantity=\"2\" price=\"3.50\"/>\n"
." </shopping>\n";

my $xs = XML::Simple->new();
my $ref = $xs->XMLin($xml);
my $stuff = ${$ref}{item};

my $q;
my $p;
my $t;
my $z;

foreach my $item ( sort keys %{$stuff}){
$q = ${$stuff}{$item}{quantity};
$p = ${$stuff}{$item}{price};
$z = $q*$p;
printf "%5.5s %2d @\$%5.2f = \$%5.2f\n",$item,$q,$p,$z;
$t += $z;
}
printf "Total \$%5.2f\n",$t;

#eos
use strict;
use XML::Twig;

use Data::Dumper;

my $xml = <<ENDXML;
<shopping>
<item name="bread" quantity="3" price="2.50"/>
<item name="milk" quantity="2" price="3.50"/>
</shopping>
ENDXML

my $xt = XML::Twig->parse( $xml );

my $price;
foreach my $item ($xt->root->children('item')) {
$price += ($item->{att}{price} * $item->{att}{quantity})
}

printf "Total Cost: %.2f\n", $price


groovy
printf '$%.2f\n', new XmlSlurper().parseText(xml).item.collect{
it.@quantity.toInteger() * it.@price.toFloat()
}.sum()
scala
val data = <shopping>
<item name="bread" quantity="3" price="2.50"/>
<item name="milk" quantity="2" price="3.50"/>
</shopping>

val res = for (
item <- data \ "item" ;
price = (item \ "@price").text.toDouble ;
qty = (item \ "@quantity").text.toInt)
yield (price * qty)

printf("$%.2f\n", res.sum)
python
from xml.dom.minidom import parseString
document = parseString(
"""<shopping>
<item name="bread" quantity="3" price="2.50"/>
<item name="milk" quantity="2" price="3.50"/>
</shopping>""").documentElement
total = sum([float(item.getAttribute('price')) *
int(item.getAttribute('quantity'))
for item in document.getElementsByTagName('item')])
print '$%.2f' % total
cpp
char input[] =
"<shopping>"
" <item name=\"bread\" quantity=\"3\" price=\"2.50\"/>"
" <item name=\"milk\" quantity=\"2\" price=\"3.50\"/>"
"</shopping>";

xml_document<> doc;
doc.parse<0>(input);
xml_node<> *shopping = doc.first_node();

float total_price = 0;
for (xml_node<> *item = shopping->first_node(); item != NULL; item = item->next_sibling())
{
float item_sum = 0;
float val;

if (string(item->name()) != "item")
continue;

for (xml_attribute<> *attr = item->first_attribute(); attr != NULL; attr = attr->next_attribute())
{
string name(attr->name());
if (name == "quantity" || name == "price")
{
stringstream v(attr->value());
v >> val;
if (item_sum)
item_sum *= val;
else
item_sum = val;
}
}
total_price += item_sum;
}

cout.setf(ios::fixed, ios::floatfield);
cout << "Total price is $" << setprecision(2) << total_price << endl;
fsharp
#r @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\System.Xml.Linq.dll"

open System
open System.Xml.Linq
//XElement Helper
let xname sname = XName.Get sname

let xmlsnippet =
let snippet = new XElement(xname "shopping")
//create bread
let bread = new XElement(xname "item")
bread.SetAttributeValue(xname "name","bread")
bread.SetAttributeValue(xname "quantity",3)
bread.SetAttributeValue(xname "price",2.50)
//add bread to snippet
snippet.Add(bread)
//create milk
let milk = new XElement(xname "item")
milk.SetAttributeValue(xname "name","milk")
milk.SetAttributeValue(xname "quantity",2)
milk.SetAttributeValue(xname "price",3.50)
//add milk to snippet
snippet.Add(milk)
snippet

let totalprice (xe: XElement) =
xe.Descendants(xname "item")
|> Seq.map(fun i -> Double.Parse(i.Attribute(xname "price").Value))
|> Seq.fold(fun acc x -> acc + x) 0.0


let xname sname = XName.Get sname
let xattr (elem: XElement) sname = elem.Attribute(xname sname).Value
let xml = XDocument.Load("xml.txt")

let shoppingCost =
xml.Descendants(xname "item")
|> Seq.map (fun i -> Double.Parse(xattr i "quantity"), Double.Parse(xattr i "price"))
|> Seq.sumBy (fun (quantity, price) -> quantity * price)
// Alternative solution that uses XML Navigation, and XPath expressions to ensure that
// the items have the required attributes
let xname sname = XName.Get sname
let xattr (elem: XElement) sname = elem.Attribute(xname sname).Value

let navigator = XPathDocument("xml.txt").CreateNavigator()
let path = XPathExpression.Compile("/shopping/item[@price][@quantity]")
let names = XmlNamespaceManager(navigator.NameTable)
path.SetContext(names)
let shoppingCost =
match path.ReturnType with
| XPathResultType.NodeSet ->
navigator.Select(path)
|> Seq.cast
|> Seq.map (fun (i: XPathNavigator) ->
if i.IsNode then
let elem = XElement.Parse(i.OuterXml)
Double.Parse(xattr elem "quantity"), Double.Parse(xattr elem "price")
else
failwith "Error in expression, expecting to see a node"
)
|> Seq.sumBy (fun (quantity, price) -> quantity * price)
| _ -> failwith "Error in expression, expecting to see a node set"
erlang
-include_lib("xmerl/include/xmerl.hrl").
-export([get_total/1]).

get_total(ShoppingList) ->
{XmlElt, _} = xmerl_scan:string(ShoppingList),
Items = xmerl_xpath:string("/shopping/item", XmlElt),
Total = lists:foldl(fun(Item, Tot) ->
[#xmlAttribute{value = PriceString}] = xmerl_xpath:string("/item/@price", Item),
{Price, _} = string:to_float(PriceString),
[#xmlAttribute{value = QuantityString}] = xmerl_xpath:string("/item/@quantity", Item),
{Quantity, _} = string:to_integer(QuantityString),
Tot + Price*Quantity
end,
0, Items),
io:format("$~.2f~n", [Total]).
ocaml
let () =
let xml = Xml.parse_file "shopping.xml" in
let res =
Xml.fold (fun total xml ->
match xml with
| Xml.Element ("item", attrs, _) ->
let quantity = float_of_string (List.assoc "quantity" attrs)
and price = float_of_string (List.assoc "price" attrs) in
total +. (quantity *. price)
| _ -> total
) 0.0 xml
in
Printf.printf "Total cost of the items: %g\n" res
csharp
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(
@"<shopping>
<item name='bread' quantity='3' price='2.50'/>
<item name='milk' quantity='2' price='3.50'/>
</shopping>");

string decimalSeparator= System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator;

double sum=0;

foreach(System.Xml.XmlNode nodo in doc.SelectNodes("/shopping/item")){
sum += int.Parse(nodo.Attributes["quantity"].InnerText) * double.Parse(nodo.Attributes["price"].InnerText.Replace(".",decimalSeparator));
}
Console.WriteLine("{0:#.00}",sum);
php
$xmlfile = simplexml_load_file('shop.xml');
$x = 0;
foreach ($xmlfile as $xml) {
// we have to declare that it's a float
$x = $x + ($xml['quantity'] * (float)$xml['price']);
}
echo $x;
$filename = "shop.xml";
if (($fp = fopen($filename, "r"))) {
while ($data = fread($fp, 4096)) {
$data = eregi_replace(">"."[[:space:]]+"."< ",">< ", $data);
if (!xml_parse($xmlparser, $data, feof($fp))) {
$reason = xml_error_string(xml_get_error_code($xmlparser));
$reason .= xml_get_current_line_number($xmlparser);
die($reason);
}
}
xml_parser_free($xmlparser);
echo $total; // Echo the total
}
haskell
File Edit Options Buffers Tools Haskell Help
import Text.ParserCombinators.Parsec
import Control.Monad
import System ( getArgs )

data Item = Item { name :: String,
quantity :: Int,
price :: Int }
deriving Show

type Basket = [Item]

item :: Parser Item
item = do string "<item name=\""
name <- manyTill letter (char '\"')
string " quantity=\""
quantity <- liftM read $ many digit
string "\" price=\""
dollars <- liftM read $ many digit
cents <- option 0 (char '.' >> (liftM read $ many digit))
string "\"/>"
return $ Item name quantity (100 * dollars + cents)

basket :: Parser Basket
basket = do string "<shopping>"
items <- manyTill item (try $ string "</shopping>")
return items

parseBasket :: String -> Basket
parseBasket input = case parse basket "Shopping Basket" input of
Left _ -> []
Right val -> val

main = do args <- getArgs
putStrLn $ show . (/100) . fromIntegral . sum . map (\(Item _ q p) -> q * p) . parseBasket $ head args
import Text.XML.HXT.Core
import Text.Printf

main :: IO ()
main = do
prices <- runX (process "basket.xml")
printf "$%.2f\n" $ sum prices

process :: FilePath -> IOSArrow XmlTree Double
process filename =
readDocument [withValidate no] filename >>>
getChildren >>>
isElem >>> hasName "shopping" >>>
getChildren >>>
isElem >>> hasName "item" >>>
getQuantity &&& getPrice >>>
arr (uncurry (*))

getQuantity :: IOSArrow XmlTree Double
getQuantity =
getAttrl >>> hasName "quantity" >>> getChildren >>>
getText >>> arr read

getPrice :: IOSArrow XmlTree Double
getPrice =
getAttrl >>> hasName "price" >>> getChildren >>>
getText >>> arr read
clojure
(println (format "Total cost of items are $%#.2f"
(->> (xml-seq (parse *xml-input-stream*))
(filter #(= :item (:tag %))) ; Remove all but the item tags
(map :attrs) ; Keep the attributes
(map (fn [e] (str "(* " (:quantity e) " " (:price e) ")"))) ; Get the total price as a sexp
(map read-string) ; "(* quantity price)" -> (* quantity price)
(map eval) ; (* quantity price) -> quantity*price
(apply +)))) ; Sum all elements
fantom
sum := 0.0
root := XParser(File(`shop.xml`).in).parseDoc.root
if (root.name == "shopping")
{
root.elems.each
{
if (it.name == "item")
{
quantity := Int.fromStr(it.get("quantity"))
price := Decimal.fromStr(it.get("price"))
sum += quantity * price;
}
}
}
echo("\$$sum")

create some XML programmatically

Given the following CSV:

bread,3,2.50
milk,2,3.50

Produce the equivalent information in XML, e.g.:

<shopping>
  <item name="bread" quantity="3" price="2.50" />
  <item name="milk" quantity="2" price="3.50" />
</shopping>
ruby
# gem install builder
require 'builder'

xml = Builder::XmlMarkup.new
xml.shopping do
xml.item(:name => "bread", :quantity => 3, :price => "2.50")
xml.item(:name => "milk", :quantity => 2, :price => "3.50")
end
xml
java
// In this solution JAXB is used to created the xml output.
// JAXB is included in Java 1.6. Runs with 1.5 if you include JAXB Jars
// in the classpath.
class Item {
// Of course you use getters and setters and declare attributes private.
// In this sample a "dirty" way is chosen to keep LOC low.
@XmlAttribute
String name;
@XmlAttribute
Integer quantity;
@XmlAttribute
Double price;
}

@XmlRootElement
class Shopping {
@XmlElement
Set<Item> items = new HashSet<Item>();
}

String line = null;
Shopping shopping = new Shopping();
try {
BufferedReader reader = new BufferedReader(new FileReader("shopping.csv"));
while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");
Item item = new Item();
item.name = parts[0];
item.quantity = Integer.parseInt(parts[1]);
item.price = Double.parseDouble(parts[2]);
shopping.items.add(item);

}
JAXB.marshal(shopping, "D:" + File.separatorChar + "shopping.auto.xml");
} catch (IOException e) {
e.printStackTrace();
}
perl
#! /usr/bin/perl
# -*- Mode: CPerl -*-

use strict;
use XML::Simple;
use Data::Dumper;

# bread,3,2.50
# milk,2,3.50
#
# Produce the equivalent information in XML, e.g.:
#
# <shopping>
# <item name="bread" quantity="3" price="2.50" />
# <item name="milk" quantity="2" price="3.50" />
# </shopping>
#

my $line;
my $item;
my $q;
my $p;
my $z;

my $xs = XML::Simple->new();
my %d = ();
while($line=<DATA>){
chomp $line;
($item,$q,$p) = split ",",$line;
$d{shopping}{item}{$item}{quantity} = $q;
$d{shopping}{item}{$item}{price} = $p;
}

$xml = $xs->XMLout(\%d, KeepRoot => 1);
print $xml,"\n";

__DATA__
bread,3,2.50
milk,2,3.50
use strict;
use XML::Writer;
use Text::CSV;

my $csv = <<ENDOFCSV;
bread,3,2.50
milk,2,3.50
ENDOFCSV

open my $fh, '<', \$csv or die "Can't open string, $!\n";
my $csv = Text::CSV->new;
my $writer = XML::Writer->new(DATA_MODE => 1, DATA_INDENT => 2);

$writer->startTag('shopping');

while (my $arr_ref = $csv->getline($fh)) {
my %attributes;
@attributes{qw/name quantity price/} =
@{$arr_ref}[0..2];
$writer->emptyTag('item' => %attributes)
}
$writer->endTag('shopping');


groovy
b = new groovy.xml.MarkupBuilder()
b.shopping {
csv.eachLine { line ->
(n, q, p) = line.split(',')
item(name:n, quantity:q, price:p)
}
}
// Groovy equivalent of Java JAXB solution
@XmlAccessorType(NONE)
class Item {
@XmlAttribute String name
@XmlAttribute Integer quantity
@XmlAttribute Double price
}

@XmlAccessorType(NONE)
@XmlRootElement
class Shopping {
@XmlElement Set<Item> items = []
}

Shopping shopping = new Shopping()
csvtext.eachLine{ line ->
(n, q, p) = line.split(',')
shopping.items << new Item(name:n, quantity:q.toInteger(), price:p.toDouble())
}
JAXB.marshal shopping, System.out
scala
<shopping>
{List("bread,3,2.50", "milk,2,3.50") map { row =>
row split ","
} map { item =>
<item name={item(0)} quantity={item(1)} price={item(2)}/>
}}
</shopping>
python
´╗┐from xml.dom import minidom

csv = """bread,3,2.50
milk,2,3.50"""

doc = minidom.Document()
shopping = doc.createElement("shopping")

for line in csv.split("\n"):
name, quantity, price = line.split(",")
el = doc.createElement("item")
el.setAttribute("name", name)
el.setAttribute("quantity", quantity)
el.setAttribute("price", price)
shopping.appendChild(el)

print shopping.toprettyxml()
from xml.etree.ElementTree import Element, SubElement, tostring

csv = """bread,3,2.50
milk,2,3.50"""

root = Element('shopping')

for line in csv.split("\n"):
name, quantity, price = line.split(",")
SubElement(root,'item', {'name' : name,
'quantity' : quantity,
'price' : price })

print tostring(root)
cpp
string input("bread,3,2.50\nmilk,2,3.50\n");

tokenizer<char_separator<char> > tokens(input, char_separator<char>(", \n"));
tokenizer<char_separator<char> >::iterator it = tokens.begin();

xml_document<> doc;
xml_node<> *shopping = doc.allocate_node(node_element, "shopping");
doc.append_node(shopping);

while (it != tokens.end()) {
xml_node<> *item = doc.allocate_node(node_element, "item");
shopping->append_node(item);

item->append_attribute(doc.allocate_attribute("name", doc.allocate_string((*it++).c_str())));
item->append_attribute(doc.allocate_attribute("quantity", doc.allocate_string((*it++).c_str())));
item->append_attribute(doc.allocate_attribute("price", doc.allocate_string((*it++).c_str())));
}

cout << doc << endl;
fsharp
#r "System.Xml.dll"
#r "System.Xml.Linq.dll"

open System
open System.Xml
open System.Xml.Linq

let data = "bread,3,2.50
milk,2,3.50"

let X name =
XName.Get(name)

let lines = data.Split( [|"\n" |], StringSplitOptions.RemoveEmptyEntries)

let document = new XDocument()
let element = new XElement(X "shopping")
document.Add(element)

lines
|> Seq.iter (fun line ->
let items = line.Split([|','|])
let item = new XElement(X "item",
new XAttribute(X "name", items.[0]),
new XAttribute(X "quantity", items.[1]),
new XAttribute(X "price", items.[2]))
element.Add(item))

let output = document.ToString();;
erlang
to_xml(ShoppingList) ->
Items = lists:map(fun(L) ->
[Name, Quantity, Price] = string:tokens(L, ","),
{item, [{name, Name}, {quantity, Quantity}, {price, Price}], []}
end, string:tokens(ShoppingList, "\n")),
xmerl:export_simple([{shopping, [], Items}], xmerl_xml).
ocaml
(* Compilation (native):
$ ocamlopt -I +csv csv.cmxa -I +xml-light xml-light.cmxa csv2xml.ml -o csv2xml
*)

let () =
let table = Csv.load "shopping.csv" in
let columns = ["name"; "quantity"; "price"] in

let xml = Xml.Element ("shopping", [],
List.rev (
List.fold_left (fun acc row ->
Xml.Element ("item",
List.combine columns row, []) :: acc) [] table)) in

print_endline (Xml.to_string_fmt xml)
csharp
string cvs ="bread,3,2.50\nmilk,2,3.50";
IList<string> rows = cvs.Split('\n');

System.Text.StringBuilder sb = new System.Text.StringBuilder("<shopping>");
foreach(string row in rows){
IList<string> data = row.Split(',');
sb.AppendFormat("<item name='{0}' quantity='{1}' price='{2}' />",data[0],data[1],data[2]);
}
sb.Append("</shopping>");
php
$xmllines = split("\n", $cvs);
foreach ($xmllines as $l) {
$xml[] = split(",", $l);
}
echo "<shopping>\n";
foreach ($xml as $x) {
echo "\t<item name=\"".$x[0]."\" quantity=\"".$x[1]."\" price=\"".$x[2]."\" />\n";
}
echo "</shopping>\n";
clojure
(defn list->xml-item [lst]
(let [[name quantity price] (map str lst)]
{:tag :item
:attrs {:name name
:quantity quantity
:price price}}))

(defn cvs->xml [r]
(->> (map #(read-string (str "(" % ")")) (line-seq r))
(map list->xml-item)
(assoc {:tag :shopping} :content)
(emit)
(with-out-str)))

(println (cvs->xml *cvs-reader*))
fantom
sum := 0.0
rows := CsvInStream(File(`shop.csv`).in).readAllRows

doc := XDoc()
doc.root = XElem("shopping")
{
root := it
rows.each |Str[] row|
{
root.add(XElem("item")
{
XAttr("name", row[0]),
XAttr("quantity", row[1]),
XAttr("price", row[2])
})
}
}

os := File(`shop.xml`).out
doc.write(os)
os.close