Oracle XMLQuery вставляет нежелательное пространство имен
Oracle 11.2
Ниже приведена урезанная версия XMLQuery
я бегу на XMLType
колонка. Когда я запускаю запрос, который просто анализирует и воссоздает сохраненный XML
нежелательные пространства имен по умолчанию и tsip вставляются в дочерние элементы родительского элемента. Обратите внимание, что пространство имен 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
:
Обратите внимание, что необходимость подстановочных знаков в пространстве имен объясняется здесь.
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>
Как мне избавиться от нежелательных пространств имен, созданных в присоединениях и заявленных элементах. Любые предложения приветствуются.
2 ответа
Если вы поиграете с различными значениями пространств имен, вы можете увидеть, что в то время как верхняя <patent>
Уровень имен пространства объявляется и включается из-за объявлений, которые вы делаете, на уровне дочернего элемента эта информация не используется так, как вы ожидаете.
XQuery извлекает пространства имен на основе тех, которые используются в узлах, рассматриваемых в этом цикле выполнения, независимо от документов в целом. Вот почему они "объявляются" каждый раз, когда XQuery проходит цикл.
В других статьях объясняется, что вы пытаетесь "проанализировать" данные и "извлечь" их, что в некоторой степени верно, и поэтому XSLT - это правильный инструмент, а не XQuery.
Я нашел одну внешнюю ссылку, которая имеет способ XQuery для удаления пространств имен и возврата вам "необработанного" XML.
Применение этого кода к вашему 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;
Немного изменив второе решение @Graham Nicol, похоже, это дает правильный ответ:
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;