For all it's usefulness XQuery never really took off the way it seems it should have done. I mean we have a query language from the W3C for XML and since XML use is pervasive... and it's kinda like SQL which is wildly successful... and there the story appears to end without the desired/expected conclusion. All the same it's becoming increasingly invaluable for us as we're using XML datatype input/output stored procedure parameters.
To demonstrate its value by example. Here's one way to generate XML using LINQ and hash table to validate against a given schema:
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Wimiro.Data.Examples {
public static class TransformXmlImperatively {
public static string GenerateCdsSpreadOutput(this string xml, string requestXml) {
var rootNode = xml.GetXmlDocument().FirstChild;
var xmlWithNewDocumentRoot = rootNode.GetProcessingInstruction();
xmlWithNewDocumentRoot += "<" + requestXml.GetResponseRootElementName()
+ " xsi:noNamespaceSchemaLocation=\"static_analysis.xsd\" "
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">";
xmlWithNewDocumentRoot += xml.GetCurvesPointsFromXml();
xmlWithNewDocumentRoot += "</" + requestXml.GetResponseRootElementName() + ">";
return xmlWithNewDocumentRoot;
}
public static string GetCurvesPointsFromXml(this string xml) {
var curveDictionary = new Dictionary<string, XElement>();
var rawDoc = XDocument.Parse(xml);
var rawElements = from elements
in rawDoc.Elements("root").Elements("row")
select elements;
var curveRoot = new XDocument(new XElement("root"));
foreach (var rawElement in rawElements) {
if (!ContainsCurve(curveDictionary, rawElement)) {
AddCurve(curveDictionary, rawElement, curveRoot);
}
FindCurve(curveDictionary, rawElement).Add(GetCurvePoint(rawElement));
}
return curveRoot.ToXml().StripRoot();
}
private static XElement FindCurve(IDictionary<string, XElement> curveDictionary,
XElement rawElement) {
return curveDictionary[rawElement.GetKey()];
}
private static XElement GetCurvePoint(XElement rawElement) {
XElement curvePoint;
curvePoint = new XElement("Point");
curvePoint.SetAttributeValue("Spread", rawElement.Attribute("Spread").Value);
curvePoint.SetAttributeValue("MaturityYears", rawElement.Attribute("MaturityYears").Value);
return curvePoint;
}
private static void AddCurve(Dictionary<string, XElement> curveDictionary,
XElement rawElement,
XDocument curveRoot) {
XElement curveElement;
curveElement = new XElement("Curve");
curveRoot.Element("root").Add(curveElement);
curveDictionary.Add(rawElement.GetKey(), curveElement);
foreach (var curveAttribute in rawElement.Attributes())
curveElement.SetAttributeValue(curveAttribute.Name, curveAttribute.Value);
curveElement.SetAttributeValue("Spread", null);
curveElement.SetAttributeValue("MaturityYears", null);
}
private static bool ContainsCurve(IDictionary<string, XElement> curveDictionary,
XElement rawElement) {
return curveDictionary.ContainsKey(rawElement.GetKey());
}
}
}
And here's the way it should have been done using XQuery:
select @xml_out.query
(' for $Ticker in distinct-values(/root/row/@Ticker)
let $Tickers := /root/row[@Ticker=$Ticker]
for $Currency in distinct-values($Tickers/@Currency)
let $Currencies := $Tickers[@Currency=$Currency]
for $Date in distinct-values($Currencies/@Date)
let $Dates := $Currencies[@Date=$Date]
return
<Curve Ticker="{$Ticker}"
Currency="{$Currency}"
Date="{$Date}">{
for $node in $Dates
return
<Point Maturity="{data($node/@MaturityYears)}"
Spread="{data($node/@Spread)}" />
}
</Curve>')
StackOverflow! For all your hardware needs.