In P.S. of this posting you can find a C# code snippet, which uses XSLT transformation + RegEx matching to get currency rate value from an XML document. Please read my question inline quoted by
//+
…
//-
comment lines group.
Thank you.
P.S. Code:
string currencyCode = "RUB";
var xml = new StringReader(
@"<gesmes:Envelope
xmlns:gesmes='http://www.gesmes.org/xml/2002-08-01'
xmlns{{EmptyNameSpace}} ='http://www.ecb.int/vocabulary/2002-08-01/eurofxref'>
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube>
<Cube time='2012-06-27'>
<Cube currency='USD' rate='1.2478' />
<Cube currency='RUB' rate='41.1252' />
<Cube currency='ZAR' rate='10.4601' />
</Cube>
</Cube>
</gesmes:Envelope>"
.Replace("{{EmptyNameSpace}}", ":ns1")
//+
// I'd like to get this code working the same way as it does now
// producing
//
// Result: EUR/RUB => 41.1252
//
// output but when the above code line will be commented
// and the below code line uncommented
//-
//.Replace("{{EmptyNameSpace}}", "")
);
var xslt = new XmlTextReader(new StringReader(
@"<xsl:stylesheet version='2.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:gesmes='http://www.gesmes.org/xml/2002-08-01'
xmlns:ns1 ='http://www.ecb.int/vocabulary/2002-08-01/eurofxref'
>
<xsl:variable name='x1' select='gesmes:Envelope/Cube/Cube/Cube[@currency=""{0}""]' />
<xsl:template match='gesmes:Envelope'>
[<xsl:apply-templates select='$x1' />]
</xsl:template>
<xsl:template match='Cube'>
<xsl:value-of select='@rate' />
</xsl:template>
</xsl:stylesheet>".Replace("{0}", currencyCode)
));
var xDoc = new XPathDocument(xml);
var xTr = new System.Xml.Xsl.XslCompiledTransform();
xTr.Load(xslt) ;
StringBuilder sb = new StringBuilder();
StringWriter writer = new StringWriter(sb);
xTr.Transform(xDoc, null, writer);
string pattern = @"\[(?'name'[0-9]*\.[0-9]*)\]";
System.Console.WriteLine(
"Result: EUR/{0} => {1}",
currencyCode,
Regex.Match(sb.ToString(), pattern)
.Groups["name"].Value);
// Result: EUR/RUB => 41.1252
As far as I can tell from looking at that code, your problems is handling the default namespace in XPath:
{{EmptyNameSpace}}is:ns1, everything’s fine – in your Xml document, the namespaceshttp://www.gesmes.org/xml/2002-08-01andhttp://www.ecb.int/vocabulary/2002-08-01/eurofxrefwith the prefixesgesmesandns1are defined; your Xml document uses identifiers such as<gesmes:Envelope>fromgesmesand others, namely<Cube>, that are not associated with any namespace. In the XSLT code, you are using XPath expressions, such as (here shortened)gesmes:Envelope/Cube/Cube/Cube, which is fine, as this expression refers to an<Envelope>element from the namespace declared with thegesmesprefix, as well as to<Cube>elements without a namespace.{{EmptyNameSpace}}to an empty string, this changes: Now,http://www.ecb.int/vocabulary/2002-08-01/eurofxrefis the default namespace of your document. Hence, the<Cube>elements in your document are considered to belong to that namespace. Your XPath expression, however, still considers the<Cube>elements that appear in the XPath as having no namespace – they do not have any namespace prefix and XPath doesn’t know about default namespaces.As a solution, you should add namespace prefixes to your XPath expression – if the
<Cube>elements belong to thehttp://www.ecb.int/vocabulary/2002-08-01/eurofxrefnamespace, your XPath should read like this:(Of course, the other XPath expressions in your XSLT have to be adapted accordingly.)
Please let me know if you need any further explanations on this – or whether I’ve gotten on the wrong track with my assumptions.
Update: Here’s what the XSLT should look like in order to work if the Xml document has the default namespace: