سؤال

لدي مستند 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>

أريد إدخالًا واحدًا فقط في علامة جذر كتبي، وهناك علامات أخرى، مثل الكتيب الموجود هناك أيضًا والتي تحتاج إلى إزالة التكرارات.أيه أفكار؟


تم تحديث التعليقات التالية.أعني بالعقد الفريدة إزالة تكرارات متعددة للعقد التي لها نفس المحتوى والبنية بالضبط.

هل كانت مفيدة؟

المحلول

حل 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>

التفسير الأمر بسيط:لكل book, ، حدد واحدًا فقط من مرات حدوثه - بحيث يكون فهرسه موجودًا جميع الكتب هو نفس الفهرس الأول لها title في جميع العناوين.

نصائح أخرى

ويمكنك استخدام المدمج في وظيفة distinct-values() ...

حل مستوحى من البرمجة الوظيفية.هذا الحل قابل للتوسيع حيث يمكنك استبدال "=" المقارنة من قبل الخاص بك مخصص منطقية local:compare($element1, $element2) وظيفة.هذه الوظيفة لديها الحالة الأسوأ التعقيد التربيعي في طول القائمة.يمكن أن تحصل 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)

وأنا تحل مشكلتي من خلال تنفيذ وظيفة البحث التفرد متكررة، تستند فقط على محتوى النص من المستند لمطابقة التفرد.

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>

واعتقد اذا كنت بحاجة الى مختلف قليلا مطابقة التكافؤ، يمكنك تغيير مطابق في خوارزمية وفقا لذلك. يجب ان تحصل على انك بدأته على أية حال.

وماذا عن الجبهة الوطنية: قيم متميزة

لإزالة التكرارات وعادة ما تستخدم وظيفة مساعد. في قضيتك انها سوف تبدو وكأنها ما يلي:

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>
};

ويمكنك استخدام هذه الوظيفة functx: functx: متميزة العميقة

لا حاجة إعادة اختراع العجلة

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top