1

Dimitre Novatchev がends-withXPath 1.0 式で複製する方法を示しているこの質問を見てきました。SelectNodesただし、通話内でのコンテキストでの実装に問題があります。

以前、私が使用していた

XmlElement root = doc.DocumentElement;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("x", root.NamespaceURI);    
XmlNodeList nodeList = doc.SelectNodes("//x:*[contains(name(.), '-notification')]", nsmgr);

必要なすべてのノードと、末尾に「s」が追加された必要のないノードが返されました(has-more-notifications)。

だから私は私に与えられた Dimitre 式を使用してみました:

XmlNodeList nodeList = doc.SelectNodes("//x:*[substring(name(.), string-length(name(.)) - string-length('-notification') +1)]", nsmgr);

これは惨めに失敗し、のルートノードが表示されnotification-data-responseます。

これは XPath への私の最初の進出であり、正規表現のように思えます - あなたはそれを理解しているか、理解していないかのどちらかです。

で終わるノードのみを返すように式を実装するにはどうすればよい-notificationですか?

アップデート

入力のサンプル:

<?xml version="1.0" encoding="UTF-8"?>
<notification-data-response xmlns="http://checkout.google.com/schema/2" serial-number="16ceae10-a9f1-4ff0-a77b-c3407f2d684a">
    <notifications>
        <new-order-notification serial-number="653417067275702-00001-7">
        </new-order-notification>
        <order-state-change-notification serial-number="653417067275702-00005-1">
        </order-state-change-notification>
        <risk-information-notification serial-number="653417067275702-00005-5">
        </risk-information-notification>
        <authorization-amount-notification serial-number="653417067275702-00005-6">
        </authorization-amount-notification>
    </notifications>
    <continue-token>CP6u9NeQJxC2y72h-MiUARgG</continue-token>
    <has-more-notifications>false</has-more-notifications>
</notification-data-response>
4

2 に答える 2

2

名前空間プレフィックスを避けたい場合は、 local-name() 関数を使用する必要があります。このようなものは、 -notification で終わるすべてのノードを提供するはずです

//node()[substring(local-name(), string-length(local-name()) - string-length('-notification')+ 1, string-length(local-name()))= ' -通知']

わかりました..私はこれをここでテストしました。XPath はオープン スタンダードであるため、すべてのツールで同様の応答が得られるはずです。

http://www.xpathtester.com/test

入力

 <?xml version="1.0"?>
<notification-data-response xmlns:x="test">
    <TPI_ADDRESSES>
        <ISPRIMARY>Y</ISPRIMARY>
        <data1>
            <x:wewe-notification/>
        </data1>
        <data2>
            <x:wewe-notification/>
        </data2>
    </TPI_ADDRESSES>
</notification-data-response>

出力

<?xml version="1.0" encoding="UTF-8"?>

<root>
  <x:wewe-notification xmlns:x="test"/>
  <x:wewe-notification xmlns:x="test"/>
</root>

有効なフォーマット可能な応答を提示するために生成されるので、ルート ノードを無視します。

ここで、xpath について詳しく説明します。

"//" -- ワイルド検索を実行して検索していることを示します。または、フル スキャンと呼びます..どのレベルのターゲット ノードが来るかは気にしないように。

「node()」 -- すべてのノードまたは現在のノードへの参照です ....

だから今: "//node()" -- 一緒に、xml 内のすべてのノードを評価しようとしていることを示します。

あなたは何を評価しますか?

名前-- ノードの名前に「-notification」が含まれているかどうかを調べます。そのためには、LHS で部分文字列関数を使用します

substring(local-name(), string-length(local-name()) - string-length('-notification')+ 1, string-length(local-name()))

RHS は検索文字列 = '-notification' です

local-name() = 接頭辞を除く任意の時点で評価しているノードの名前を指定します string-length() - ノード名の長さ

于 2012-08-10T14:44:05.570 に答える
0

Dimitre の回避策はうまく機能します。部分文字列化された「終了」を、探している文字列定数と比較するだけです。つまり、次のようになります。

SelectNodes("//x:*['-notification'=substring(name(.), string-length(name(.)) 
           - string-length('-notification') +1)]")

興味深いことに、//パスをより具体的にすることでワイルドカードを回避できれば、大きなドキュメントでのクエリのパフォーマンスが大幅に向上します。

編集

これをテストした方法は次のとおりです(MS Visual Studioのxsltパーサーで、これは1.0です):

<root>
    <nodeendsin-notification></nodeendsin-notification>
    <alsonodeendsin-notification></alsonodeendsin-notification>
    <nopethisis-notifications></nopethisis-notifications>
    <idontcontainatall></idontcontainatall>
</root>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="/root">
        <root>
            <xsl:apply-templates/>
        </root>
    </xsl:template>
    <xsl:template match="*['-notification'=substring(name(.), string-length(name(.)) - string-length('-notification') +1)]">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="@* | node()">
    </xsl:template>
</xsl:stylesheet>

「通知」で終わるノードだけを返します

<root>
    <nodeendsin-notification></nodeendsin-notification>
    <alsonodeendsin-notification></alsonodeendsin-notification>
</root>
于 2012-08-10T14:20:02.177 に答える