xquery / xpath, сравнивающий все кроме указанного узла c - PullRequest
1 голос
/ 23 апреля 2020

У меня есть два документа, которые я хочу сравнить, но я хочу опустить сравнение двух узлов, которые, как я знаю, будут разными, например:

<record>
   <core>
      <title>test1</title>
      <description>testDesc1</description>
      <ingestDate>2019-03-01</ingestDate>
   </core>
   <specialized>
      <item>testItem1</item>
      <itemRecordingTime>2019-12-05T08:15:00</itemRecordingTime>
   </specialized>
</record>

и

<record>
   <core>
      <title>test1</title>
      <description>testDesc1</description>
      <ingestDate>2020-03-01</ingestDate>
   </core>
   <specialized>
      <item>testItem1</item>
      <itemRecordingTime>2020-12-05T08:15:00</itemRecordingTime>
   </specialized>
</record>

Is в xquery или xpath есть возможность сравнить эти два документа, кроме узлов <ingestDate> и <itemRecordingTime>?

Ответы [ 2 ]

3 голосов
/ 23 апреля 2020

Я бы нормализовал содержимое, удалив элементы, которые вы не хотите сравнивать, и затем использовал бы fn:deep-equal() для сравнения нормализованных документов.

Ниже приведен пример как вы можете использовать XSLT для удаления элементов с xdmp:xslt-eval() (вы также можете xdmp:xslt-invoke установить таблицу стилей вместо eval):

xquery version "1.0-ml";

declare function local:compare($a, $b) {
  let $xslt := 
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
      <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
      <!--Remove the elements that we don't want to compare -->
      <xsl:template match="ingestDate | itemRecordingTime"/>
  </xsl:stylesheet>
  let $normalized-a := xdmp:xslt-eval($xslt, $a)
  let $normalized-b := xdmp:xslt-eval($xslt, $b)
  return fn:deep-equal($normalized-a, $normalized-b)
};

let $doc-a := 
<record>
   <core>
      <title>test1</title>
      <description>testDesc1</description>
      <ingestDate>2019-03-01</ingestDate>
   </core>
   <specialized>
      <item>testItem1</item>
      <itemRecordingTime>2019-12-05T08:15:00</itemRecordingTime>
   </specialized>
</record>
let $doc-b :=
<record>
   <core>
      <title>test1</title>
      <description>testDesc1</description>
      <ingestDate>2020-03-01</ingestDate>
   </core>
   <specialized>
      <item>testItem1</item>
      <itemRecordingTime>2020-12-05T08:15:00</itemRecordingTime>
   </specialized>
</record>

return
  local:compare($doc-a, $doc-b)
0 голосов
/ 24 апреля 2020

Alternative. Вы можете использовать XPath для извлечения текстовых узлов и их объединения. Сохраните результаты в 2 переменных и выполните сравнение.

XPath 2.0:

string-join(//*/*[position()<last()]/text()[normalize-space()])

или

string-join(//*[not(name()="ingestDate" or name()="itemRecordingTime")]/text()[normalize-space()])

Вывод:

String='test1testDesc1testItem1'

XPath 1.0 (массивный):

translate(concat(substring(normalize-space(string(//core)),1,string-length(normalize-space(string(//core)))-(string-length(normalize-space(string(//ingestDate)))+1)),substring(normalize-space(string(//specialized)),1,string-length(normalize-space(string(//specialized)))-(string-length(normalize-space(string(//itemRecordingTime)))+1)))," ","")

Вывод:

String='test1testDesc1testItem1'
...