0

特定のパターンの値が検出された場合に XML データ シーケンスからタイムスタンプを返す関数を XQuery で作成しようとしています。データは、実際にはシステムの API メッセージのテスト ログです。

サンプル XML データは、以下のスニペットのようになります。シーケンスが見つかった場合、タイムスタンプ (TIME タグ) はパターン エントリの各行で同じであると見なされます。

を検出して返す必要がある特定のパターンTIMEは、4 つの<FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE>エントリが順番に続き、その後に 4 つのエントリが直接続く場所<FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE>です。すべて同じタイムスタンプです。

<SEQUENCE><TIME>13.00</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>INVALID</MODE></SEQUENCE>
<SEQUENCE><TIME>13.00</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>INVALID</MODE></SEQUENCE>
<SEQUENCE><TIME>13.00</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>SINGLE</MODE></SEQUENCE>
<SEQUENCE><TIME>13.00</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>SINGLE</MODE></SEQUENCE>
<SEQUENCE><TIME>13.00</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>SINGLE</MODE></SEQUENCE>
<SEQUENCE><TIME>13.00</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>SINGLE</MODE></SEQUENCE>
<SEQUENCE><TIME>14.05</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE></SEQUENCE>
<SEQUENCE><TIME>14.05</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE></SEQUENCE>
<SEQUENCE><TIME>14.05</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE></SEQUENCE>
<SEQUENCE><TIME>14.05</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE></SEQUENCE>
<SEQUENCE><TIME>14.05</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE></SEQUENCE>
<SEQUENCE><TIME>14.05</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE></SEQUENCE>
<SEQUENCE><TIME>14.05</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE></SEQUENCE>
<SEQUENCE><TIME>14.05</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE></SEQUENCE>
<SEQUENCE><TIME>15.94</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>INVALID</MODE></SEQUENCE>
<SEQUENCE><TIME>15.94</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>INVALID</MODE></SEQUENCE>

私が定義しようとした関数は次のとおりですが、実行時エラーが発生し'empty sequence not allowed'ます。残念ながら、ブレークポイントを設定してこれをデバッグできる IDE がありませんFOR

declare function local:get_multi_track_sequence_time( $msgSeq as element()*) as xs:double {
    for $row in $msgSeq
    where some $entry in $row satisfies($entry/SEQUENCE[TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
                    /following-sibling::SEQUENCE[TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
                    /following-sibling::SEQUENCE[TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
                    /following-sibling::SEQUENCE[TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
                    /following-sibling::SEQUENCE[TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']
                    /following-sibling::SEQUENCE[TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']
                    /following-sibling::SEQUENCE[TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']
                    /following-sibling::SEQUENCE[TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI'] )
    return data($row/SEQUENCE/TIME)
};

ありがとう。私は XQuery の比較的初心者です。

---------------------編集 - 提案からのアイデアでテスト機能を追加-------------------- -

すでに受け取った提案に感謝します。与えられた有用な情報に基づいて、次の自己完結型のテスト関数を作成しました-関数は次の兄弟のものと一致しません。

dataこの関数は、テスト シーケンスを含む変数を作成します。関数はそのままでは空のシーケンスを返します。要件は、シーケンス内の 4 つのエントリがあり、その後にシーケンス内の 4 つのエントリが直接続く14.050000スカラーを示すために返されることです (つまり、テスト データのTIME )。TIME<FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE><FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE>14.050000

(興味深いことに、最初の式のみが使用された場合、つまり、TRACK_STATUS/VALID のすべての出現に一致し、後続の兄弟一致が指定されていない場合、double のシーケンスが正常に返されます。)

declare function local:get_multi_track_sequence_time( ) as xs:double* {

    let $data as element()* := (

<SEQUENCE><TIME>13.04080</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>INVALID</MODE></SEQUENCE>,
<SEQUENCE><TIME>13.04080</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>INVALID</MODE></SEQUENCE>,
<SEQUENCE><TIME>13.05000</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE></SEQUENCE>,
<SEQUENCE><TIME>13.06900</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>SINGLE</MODE></SEQUENCE>,
<SEQUENCE><TIME>13.06900</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>SINGLE</MODE></SEQUENCE>,
<SEQUENCE><TIME>14.05000</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE></SEQUENCE>,
<SEQUENCE><TIME>14.05000</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE></SEQUENCE>,
<SEQUENCE><TIME>14.05000</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE></SEQUENCE>,
<SEQUENCE><TIME>14.05000</TIME><TAG>2900</TAG><FIELD>TRACK_STATUS</FIELD><MODE>VALID</MODE></SEQUENCE>,
<SEQUENCE><TIME>14.05000</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE></SEQUENCE>,
<SEQUENCE><TIME>14.05000</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE></SEQUENCE>,
<SEQUENCE><TIME>14.05000</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE></SEQUENCE>,
<SEQUENCE><TIME>14.05000</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>MULTI</MODE></SEQUENCE>,
<SEQUENCE><TIME>15.06700</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>SINGLE</MODE></SEQUENCE>,
<SEQUENCE><TIME>15.06700</TIME><TAG>2900</TAG><FIELD>MULTI_CHAN_IND</FIELD><MODE>SINGLE</MODE></SEQUENCE>

)

    for $entry in $data
    where $entry/self::SEQUENCE
            [TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
          /following-sibling::*[1]/self::SEQUENCE
            [TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
          /following-sibling::*[1]/self::SEQUENCE
            [TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
          /following-sibling::*[1]/self::SEQUENCE
            [TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
          /following-sibling::*[1]/self::SEQUENCE
            [TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']
          /following-sibling::*[1]/self::SEQUENCE
            [TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']
          /following-sibling::*[1]/self::SEQUENCE
            [TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']
          /following-sibling::*[1]/self::SEQUENCE
            [TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']

    return data($entry/TIME)
};
4

3 に答える 3

1

あなたは成功に近づいています。

いくつかのクリーンアップが必要です。まず、 と の組み合わせはfor $row in $msgSeqsome $entry in $row同じ要素シーケンス ( として渡されたシーケンス$msgSeq) を反復処理しています。$msgSeq の値として何を渡しているのか、あなたの質問からは明らかではありませんが、where some $entry in $row/*(暗黙の存在量化を利用して)単にwhere $row/*/SEQUENCE ....

次に、問題の説明は、特定のプロパティを持つ 8 つの隣接する SEQUENCE 要素のシーケンス (の親) を検索することを示唆しています。ただし、長い XPath 式は隣接関係を必要としません 。SEQUENCE という名前の $foo の後続のすべて$foo/following-sibling::SEQUENCEの兄弟に一致します。パスを制約してアイテムを隣接させるには、フォームのステップを変更する必要があります

.../following-sibling::SEQUENCE[ ... conditions ... ]

.../following-sibling::*[1]/self::SEQUENCE[ ... ]

もちろん、次の兄弟が SEQUENCE であることが保証されている場合、これは短くすることができますが、明確さが失われる可能性があります。

3 番目に、あなたの宣言は、ちょうど 1 つの double を返すことを示しています。しかし、関数本体が正確に 1 つの double を返すことは保証されていないため、悲観的なプロセッサによる厳密な静的型分析は、それを拒否する可能性があります。私が最初に目にするものは次のとおりです。

  • $row に複数の SEQUENCE 要素が含まれている場合、1data($row/SEQUENCE/TIME)つだけでなく複数の TIME 値が返されます。すべての SEQUENCE/TIME 値が同じであると確信している場合[1]は、この式が (たとえば) 8 や 20 ではなく、多くても 1 つの値を返すようにする方法として、加算を行います。

  • 何も一致しない場合、関数は実際には、1 つの double の単一のシーケンスではなく、空のシーケンスを返します。

  • $msgSeq 内の複数の $row が条件を満たす場合、条件を満たすdata($row/SEQUENCE/TIME)各 $row を評価することによって形成された一連の結果を返します。データの形状は、これが決して起こらないことを保証するかもしれませんが、静的アナライザーがそれを知ることはほとんどありません.

以下に示す関数の修正された形式は、(a) $msgSeq が SEQUENCE 要素のシーケンスであり、(b) 記述したイベント シーケンスの最初のイベントであるすべての SEQUENCE 要素を検索し、その時間を返すことを前提としています。スタンプ (したがって、関数は全体として 0 個以上の double を返しますdouble。xs:time の代わりに時間と分の表現として何を使用する必要があるかは尋ねません。それはあなたとあなたの工学的良心の間です。 .

declare function local:get_multi_track_sequence_time( 
    $msgSeq as element()*
) as xs:double* {
for $entry in $msgSeq

where $entry/self::SEQUENCE
         [TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
      /following-sibling::*[1]/self::SEQUENCE
         [TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
      /following-sibling::*[1]/self::SEQUENCE
         [TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
      /following-sibling::*[1]/self::SEQUENCE
         [TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID']
      /following-sibling::*[1]/self::SEQUENCE
         [TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']
      /following-sibling::*[1]/self::SEQUENCE
         [TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']
      /following-sibling::*[1]/self::SEQUENCE
         [TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']
      /following-sibling::*[1]/self::SEQUENCE
         [TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI'] 
return data($entry/TIME)
};

質問に示されている SEQUENCE 要素のシーケンスがこの関数に渡されると、数値 14.05 が返されます。

于 2012-09-24T16:39:43.227 に答える
0

これがエラーをスローする理由は、関数が何も返さない (空のシーケンス) ためですが、. を返すように宣言されていxs:doubleます。Saxonでクエリを実行すると、次のようなより有益なエラー メッセージが表示されます。

関数 local:get_multi_track_sequence_time() の結果として空のシーケンスは許可されません

次の質問は、関数が常に double を返す必要があるか、それともas空のシーケンスを返す可能性を許容するように宣言を変更する必要があるかということです。where同様に、クエリの記述方法によっては、句を満たす行ごとに 1 つずつ、複数の結果が返される可能性があります。それも型エラーを引き起こします。それを許可しますか?

where句が 1 つの行に対してのみ満たされる場合でも、複数のタイムスタンプを返すことになります。

return data($row/SEQUENCE/TIME)

これは、 の要素の子である の子であるすべての要素を選択するため<TIME>です。代わりに、あなたが望む<SEQUENCE>$row

return data($row/SEQUENCE[1]/TIME)

同様に、 に関しては、次の兄弟だけでなく、次の兄弟にアクセスしようとしていることを示すためにfollowing-sibling::を使用することを忘れないでください。[1]

.../following-sibling::SEQUENCE[1][TAG='2900' and FIELD='TRACK_STATUS'
  and MODE='VALID']...

これにより、パフォーマンスが向上するだけでなく、where句が誤検出を起こさないようにする必要があります。

于 2012-09-24T16:30:28.317 に答える
0

返されたシーケンスの最初の値で正しいスカラー時間を与える次の作業関数があります。

declare function local:get_multi_track_sequence_times( $msgSeq as element()* ) as xs:double* {
    let $data := (<ROOT>{$msgSeq}</ROOT>)
    let $s1 := $data/SEQUENCE[TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID'],
        $s2 := $s1/following-sibling::SEQUENCE[TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID'],
        $s3 := $s2/following-sibling::SEQUENCE[TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID'],    
        $s4 := $s3/following-sibling::SEQUENCE[TAG='2900' and FIELD='TRACK_STATUS' and MODE='VALID'],    
        $s5 := $s4/following-sibling::SEQUENCE[TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI'],
        $s6 := $s5/following-sibling::SEQUENCE[TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI'],
        $s7 := $s6/following-sibling::SEQUENCE[TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI'],
        $s8 := $s7/following-sibling::SEQUENCE[TAG='2900' and FIELD='MULTI_CHAN_IND' and MODE='MULTI']

    return $s8/TIME           
};
于 2012-09-27T12:37:43.957 に答える