0

この投稿のPSには、XSLT変換とRegExマッチングを使用してXMLドキュメントから通貨レート値を取得するC#コードスニペットがあります。によって引用された私の質問をインラインで読んでください

// +

..。

//-

コメント行グループ。

ありがとうございました。

PSコード:

   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
4

1 に答える 1

0

そのコードを見ればわかる限り、問題はXPathでデフォルトの名前空間を処理することです。

  • {{EmptyNameSpace}}である限り:ns1、すべてが正常です。Xmlドキュメントでは、名前空間http://www.gesmes.org/xml/2002-08-01http://www.ecb.int/vocabulary/2002-08-01/eurofxrefプレフィックスが定義されてgesmesいます。ns1Xmlドキュメントは、<gesmes:Envelope>fromなどの識別子を使用します。gesmesつまり<Cube>、どの名前空間にも関連付けられていません。XSLTコードでは、(ここでは短縮された)などのXPath式を使用しています。gesmes:Envelope/Cube/Cube/Cubeこの式は、プレフィックス<Envelope>付きで宣言された名前空間の要素と、名前空間のない要素を参照するためです。gesmes<Cube>
  • {{EmptyNameSpace}}空の文字列に設定すると、次のように変更されます。これがhttp://www.ecb.int/vocabulary/2002-08-01/eurofxrefドキュメントのデフォルトの名前空間です。したがって、<Cube>ドキュメント内の要素はその名前空間に属していると見なされます。ただし、XPath式は、<Cube>XPathに表示される要素に名前空間がないと見なします。これらの要素には名前空間プレフィックスがなく、XPathはデフォルトの名前空間を認識しません。

解決策として、XPath式に名前空間プレフィックスを追加する必要があります-<Cube>要素が名前空間に属している場合、 http://www.ecb.int/vocabulary/2002-08-01/eurofxrefXPathは次のようになります。

gesmes:Envelope/ns1:Cube/ns1:Cube/ns1:Cube

(もちろん、XSLT内の他のXPath式はそれに応じて適合させる必要があります。)

これについてさらに説明が必要な場合、または私が私の仮定で間違った方向に進んだかどうかを教えてください。

更新: Xmlドキュメントにデフォルトの名前空間がある場合に機能するためにXSLTがどのように表示されるかを次に示します。

<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/ns1:Cube/ns1:Cube/ns1:Cube[@currency="RUB"]'/>

    <xsl:template match='gesmes:Envelope'>
        [<xsl:apply-templates select='$x1'/>]
    </xsl:template>

    <xsl:template match='ns1:Cube'>
        <xsl:value-of select='@rate'/>
    </xsl:template>

</xsl:stylesheet>
于 2012-06-28T19:39:44.450 に答える