2016-07-29 1 views
10

Oracle 11.2Oracle XMLQuery вставка нежелательных имена

Ниже урезанная версия XMLQuery я бег на XMLType колонки. Когда я запускаю запрос, который просто анализирует и воссоздает сохраненные XML, 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Обратите внимание, что пространство имен tsxm не вставлено, это связано с тем, что оно не равно пространству имен по умолчанию. Этот запрос ничего не делает и может быть легко переписан, но реальный (гораздо больший) запрос использует эту же методологию, поэтому поэтому я размещение вопроса в этом формате.

создать таблицу:

CREATE TABLE XML_DOCUMENT_TMP 
(
    DOCUMENT_ID NUMBER(12)      NOT NULL, 
    XML_DATA  SYS.XMLTYPE      NOT NULL, 
    CREATED_DATE TIMESTAMP(6)     NOT NULL 
); 

Вставьте некоторые данные (которые должны иметь пространство имен, как это):

insert into XML_DOCUMENT_TMP 
(document_id,created_date,xml_data) 
values(1,sysdate, 
'<patent xmlns="http://schemas.thomson.com/ts/20041221/tsip" 
    xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip" 
    xmlns:tsxm="http://schemas.thomson.com/ts/20041221/tsxm" 
    tsip:action="replace" tsip:cc="CA" tsip:se="2715340" tsip:ki="C"> 
    <accessions tsip:action="replace"> 
     <accession tsip:src="wila" tsip:type="key">CA-2715340-C</accession> 
     <accession tsip:src="tscm" tsip:type="tscmKey">CA-2715340-C-20150804</accession> 
    </accessions> 
    <claimed tsip:action="replace"> 
    < claimsTsxm tsip:lang="en"> 
      <tsxm:heading tsxm:align="left">We Claim:</tsxm:heading> 
      <claimTsxm tsip:no="1" tsxm:num="1" tsip:type="main">1. power.  </claimTsxm> 
     </claimsTsxm> 
    </claimed> 
</patent> 
'); 

Запускает XMLQuery:

Обратите внимание на необходимости пространства имен подстановочного является разъяснено here

WITH tmpTable AS (
SELECT * FROM XML_DOCUMENT_TMP cm) 
SELECT tt.xml_data , 
XMLQuery('declare default element namespace "http://schemas.thomson.com/ts/20041221/tsip"; 
    declare namespace tsip="http://schemas.thomson.com/ts/20041221/tsip"; 
    declare namespace tsxm="http://schemas.thomson.com/ts/20041221/tsxm"; 


    return   
    <patent>{$m/*:patent/@*} 
    { 
    for $i in $m/*:patent/* 
     return $i 
    } 
    </patent>' 
     PASSING tt.xml_data as "m" RETURNING CONTENT) newXml 
FROM tmpTable tt 
WHERE tt.document_id in (1); 

Возвращает:

<patent xmlns="http://schemas.thomson.com/ts/20041221/tsip" xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip" tsip:action="replace" tsip:cc="CA" tsip:se="2715340" tsip:ki="C"> 
    <accessions xmlns="http://schemas.thomson.com/ts/20041221/tsip" xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip" tsip:action="replace"> 
     <accession tsip:src="wila" tsip:type="key">CA-2715340-C</accession> 
     <accession tsip:src="tscm" tsip:type="tscmKey">CA-2715340-C-20150804</accession> 
    </accessions> 
    <claimed xmlns="http://schemas.thomson.com/ts/20041221/tsip" xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip" tsip:action="replace"> 
     <claimsTsxm tsip:lang="en"> 
      <tsxm:heading xmlns:tsxm="http://schemas.thomson.com/ts/20041221/tsip" tsxm:align="left">We Claim:</tsxm:heading> 
      <claimTsxm tsip:no="1" xmlns:tsxm="http://schemas.thomson.com/ts/20041221/tsip" tsxm:num="1" tsip:type="main">1. power.</claimTsxm> 
     </claimsTsxm> 
</claimed> 

Как избавиться от нежелательных пространств имен, созданных в присоединениях и утверждал элементы. Любые предложения оценены.

+0

Один быстрых и грязный способ будет обрабатывать ваш вывод с помощью XSLT тождественного преобразования. Кажется, слишком много, я бы не хотел называть это лучшим решением, если только оно не оказалось единственным, но я в этом сомневаюсь. – Flynn1179

+0

@ Flynn1179 Это решение (выполнение обработки XML в XMLQuery) заключается в том, чтобы избежать использования xslt, который слишком медленный (для больших XMLTypes). –

+0

Не могли бы вы попробовать «DBMS_XMLDOM.REMOVEATTRIBUTE»? Я не уверен, что это рабочее решение. – Mark

ответ

2

Если вы играете с различными значениями пространств имен, вы можете видеть, что, пока верхний уровень <patent> объявляет и включает пространства имен из-за заявлений, которые вы делаете, на уровне дочерних элементов эта информация не используется в который вы ожидаете.

XQuery извлекает пространства имен на основе тех, которые используются в узлах, рассматриваемых в этом цикле выполнения, независимо от документов в целом. Вот почему они «повторно объявляются» каждый раз, когда XQuery обходит цикл.

Другие статьи объясняют, что то, что вы пытаетесь сделать, это «разбор» данных, а также «Извлечь» его, что верно в некоторой степени, и поэтому XSLT является правильным инструментом, а не XQuery.

Одна внешняя ссылка, которую я нашел, которая имеет способ XQuery для удаления пространств имен и поэтому возвращает вам «необработанный» XML: here.

Применяя этот код на свой запрос XQuery получил меня:

SELECT xmlquery('xquery version "1.0"; (: :) 
      declare default element namespace 
         "http://www.somewherein.uk/ns/1.0"; (: :) 

      declare function local:strip-namespace($inputRequest as element()) as element() 
      { 
       element {xs:QName(local-name($inputRequest))} 
       { 
        for $child in $inputRequest /(@*,node()) 
        return 
         if ($child instance of element()) 
         then local:strip-namespace($child) 
         else $child 
       } 
      }; (: :) 

      <patent> 
      { 
      for $s in /*:patent/* 
       return local:strip-namespace($s) 
      } 
      </patent>' 
      PASSING cmf.XML_DATA 
      RETURNING content) 
FROM XML_DOCUMENT_TMP cmf WHERE cmf.DOCUMENT_ID=1 

Некоторые дальнейшего редактирования у меня ниже, я думаю, это то, что вы были после (пространств имен, определенных на patent уровне)

SELECT xmlquery('xquery version "1.0"; (: :) 
      declare default element namespace 
         "http://www.somewherein.uk/ns/1.0"; (: :) 

      declare function local:strip-namespace($inputRequest as element()) as element() 
      { 
       element {fn:name($inputRequest)} 
       { 
        for $child in $inputRequest /(@*,node()) 
        return 
         if ($child instance of element()) 
         then local:strip-namespace($child) 
         else $child 
       } 
      }; (: :) 

      <patent> 
      { 
      for $s in /(*:patent, node()) 
       return local:strip-namespace($s) 
      } 
      </patent>' 
      PASSING cmf.XML_DATA 
      RETURNING content) 
FROM XML_DOCUMENT_TMP cmf WHERE cmf.DOCUMENT_ID=1; 

Как указано ниже, это привело к некоторому дублированию кода цикла из-за некоторых проблем в XPath. Это также означало, что пространство имен txsm было объявлено пару раз; XQuery объявляет его «в первый раз», когда он сталкивается с пространством имён, используемым им, когда он ходит по этой ветке дерева, что означает, что если есть братья и сестры, которые используют ns, то он будет объявлен несколько раз.Перемещая явное размещение декларации обратно к родительскому узлу, мы можем это исключить.

SELECT xmlquery('xquery version "1.0"; (: :) 
      declare default element namespace "http://schemas.thomson.com/ts/20041221/tsip"; (: :) 
      declare namespace tsip="http://schemas.thomson.com/ts/20041221/tsip"; (: :) 
      declare namespace tsxm="http://schemas.thomson.com/ts/20041221/tsxm"; (: :) 

      declare function local:strip-namespace($inputRequest as element()) as element() 
      { 
       element {fn:name($inputRequest)} 
       { 
        for $child in $inputRequest /(@*,node()) 
        return 
         if ($child instance of element()) 
         then local:strip-namespace($child) 
         else $child 
       } 
      }; (: :) 

      <patent xmlns:tsxm="http://schemas.thomson.com/ts/20041221/tsxm" xmlns:tsip="http://schemas.thomson.com/ts/20041221/tsip"> 
      { 
      for $s in /*:patent/* 
       return local:strip-namespace($s) 
      } 
      </patent>' 
      PASSING cmf.XML_DATA 
      RETURNING content) 
FROM XML_DOCUMENT_TMP cmf WHERE cmf.DOCUMENT_ID=1; 
+0

Я видел эту ссылку, но я не мог заставить «объявлять функцию» работать. Я получаю: ORA-19193: XQST0045: Это статическая ошибка, если имя функции в объявлении функции находится в одном из следующих пространств имен: http://www.w3.org/XML/1998/namespace ... Если вы можете опубликовать рабочую измененную версию моего xQuery, тогда вы можете с радостью получить баллы. –

+0

Не совсем совершенен, но, добавив «локальное» пространство имен в функцию delcaration, я получил ее до вызова функции. Теперь он имеет несоответствие типа (% s 'против'% s' странно) –

+0

Это приличное усилие. Я заметил, что вы не объявили $ inputRequest, как это было предложено в вашей ссылке (поскольку оно вызывает ошибку ORA-19112). Интересно, проблема в этом? –

1

второго решения о внесении изменений в @Graham Никол слегка, это, кажется, чтобы дать правильный ответ:

SELECT xmlquery('xquery version "1.0"; 
     declare default element namespace 
        "http://schemas.thomson.com/ts/20041221/tsip"; 

     declare function local:strip-namespace($inputRequest as element()) as element() 
     { 
      element {fn:name($inputRequest)} 
      { 
       for $child in $inputRequest /(@*,node()) 
       return 
        if ($child instance of element()) 
        then local:strip-namespace($child) 
        else $child 
      } 
     }; 


     <patent>{/*:patent/@*} 
     { 
     for $s in /*:patent/* 
      return local:strip-namespace($s) 
     } 
     </patent> 
     ' 
     PASSING cmf.XML_DATA 
     RETURNING content) 
FROM XML_DOCUMENT_TMP cmf WHERE cmf.DOCUMENT_ID=1; 
+0

Да, это похоже на то же самое. Единственное различие, которое у нас есть, это «автоматический» и «явный» список пространств имен в верхнем элементе '', что вызывает изменение в том, как пространства имен« распространяются »сами. –

+0

@graham мы не можем жестко закодировать объявления ns в , потому что они меняются, они должны поступать из xml. У нас есть только объявления ns в корневом элементе, поэтому {/ *: patent/@ *} должно быть в порядке. –

 Смежные вопросы

  • Нет связанных вопросов^_^