16

その場で生成する XML ドキュメントがあり、そこから重複するノードを削除する関数が必要です。

私の関数は次のようになります。

declare function local:start2() {
    let $data := local:scan_books()
    return <books>{$data}</books>
};

サンプル出力は次のとおりです。

<books>
  <book>
    <title>XML in 24 hours</title>
    <author>Some Guy</author>  
  </book>
  <book>
    <title>XML in 24 hours</title>
    <author>Some Guy</author>  
  </book>
</books>

私の本のルートタグに1つのエントリだけが必要で、重複を削除する必要があるパンフレットなど、他のタグもあります。何か案は?


以下のコメントを更新しました。一意のノードとは、まったく同じ内容と構造を持つ複数のノードを削除することを意味します。

4

7 に答える 7

17

よりシンプルで直接的なワンライナー XPath ソリューション:

次の XPath 式を使用するだけです。

  /*/book
        [index-of(/*/book/title, 
                  title
                 )
                  [1]
        ]

たとえば、次の XML ドキュメントに適用すると、次のようになります

<books>
    <book>
        <title>XML in 24 hours</title>
        <author>Some Guy</author>
    </book>
    <book>
        <title>Food in Seattle</title>
        <author>Some Guy2</author>
    </book>
    <book>
        <title>XML in 24 hours</title>
        <author>Some Guy</author>
    </book>
    <book>
        <title>Food in Seattle</title>
        <author>Some Guy2</author>
    </book>
    <book>
        <title>How to solve XPAth Problems</title>
        <author>Me</author>
    </book>
</books>

上記の XPath 式は、次のノードを正しく選択します

<book>
    <title>XML in 24 hours</title>
    <author>Some Guy</author>
</book>
<book>
    <title>Food in Seattle</title>
    <author>Some Guy2</author>
</book>
<book>
    <title>How to solve XPAth Problems</title>
    <author>Me</author>
</book>

説明は簡単です: all-booksのインデックスがall-titlesの最初のインデックスと同じになるbookように、その出現箇所を 1 つだけ選択します。title

于 2009-03-20T14:01:46.397 に答える
5

組み込みdistinct-values()関数を使用できます...

于 2010-03-11T05:44:51.533 に答える
2

関数型プログラミングに触発されたソリューション。このソリューションは、 「=」比較を独自のブールlocal:compare($element1, $element2)関数で置き換えることができるという点で拡張可能です。この関数は、リストの長さに最悪の場合の2 次複雑度があります。事前にリストを並べ替えて、直後の後続とのみ比較することで、n(log n)複雑になる可能性があります。

私の知る限り、fn:distinct-values(または) 関数ではカスタムビルドの比較関数fn:distinct-elementsを使用できません。

declare function local:deduplicate($list) {
  if (fn:empty($list)) then ()
  else 
    let $head := $list[1],
      $tail := $list[position() > 1]
    return
      if (fn:exists($tail[ . = $head ])) then local:deduplicate($tail)
      else ($head, local:deduplicate($tail))
};

let $list := (1,2,3,4,1,2,1) return local:deduplicate($list)
于 2010-07-01T09:31:42.217 に答える
1

一意性マッチングのためにドキュメントのテキスト コンテンツのみに基づいて、再帰的な一意性検索機能を実装することで問題を解決しました。

declare function ssd:unique-elements($list, $rules, $unique) {
    let $element := subsequence($rules, 1, 1)
    let $return :=
    if ($element) then
        if (index-of($list, $element) >= 1) then
            ssd:unique-elements(insert-before($element, 1, $list), subsequence($rules, 2), $unique)
        else <test>
            <unique>{$element}</unique>
            {ssd:unique-elements(insert-before($element, 1, $list), subsequence($rules, 2), insert-before($element, 1, $unique))/*}
            </test>
    else ()
    return $return
};

次のように呼び出されます。

declare function ssd:start2() {
    let $data := ()
    let $sift-this := 
       <test>
           <data>123</data>
           <data>456</data>
           <data>123</data>
           <data>456</data>
           <more-data>456</more-data>
       </test>
    return ssd:unique-elements($data, $sift-this/*, ())/*/*
};

ssd:start2()

出力:

<?xml version="1.0" encoding="UTF-8"?>
<data>123</data>
<data>456</data>

少し異なる同等性マッチングが必要な場合は、それに応じてアルゴリズムのマッチングを変更できると思います。とにかく始める必要があります。

于 2009-03-13T22:50:38.077 に答える
1

fn:distinct-values はどうですか?

于 2010-05-29T19:02:42.727 に答える
1

重複を削除するには、通常、ヘルパー関数を使用します。あなたの場合、次のようになります。

declare function local:remove-duplicates($items as item()*) 
as item()*
{
  for $i in $items
  group by $i
    return $items[index-of($items, $i)[1]]
};

declare function local:start2() {
    let $data := local:scan_books()
    return <books>{local:remove-duplicates($data)}</books>
};
于 2017-04-13T09:56:07.177 に答える
1

この functx 関数を使用できます: functx:distinct-deep

車輪を再発明する必要はありません

于 2014-11-27T03:08:06.367 に答える