2014-12-15 10 views
3

У меня проблема с обновлением значений xmlType в oracle. мне нужно изменить XML ищет похожее на следующее:Как избежать специальных символов при обновлении XML в oracle SQL

<a> 
    <b>Something to change here</b> 
    <c>Here is some narrative containing weirdly escaped &lt;tags>\&lt;/tags> </c> 
</a> 

То, что я хочу добиться того, чтобы изменить < б /> без изменения < с />

К сожалению следующее modifyXml:

select 
    updatexml(XML_TO_MODIFY, '/a/b/text()', 'NewValue') 
from dual; 

возвращает это:

<a> 
    <b>NewValue</b> 
    <c>Here is some narrative containing weirdly escaped &lt;tags&gt;&lt;/tags&gt; </c> 
</a> 

, как вы можете видеть, «>» сбежал.

То же самое происходит на XMLQUERY (новый, не осуждается версия updateXml):

select /*+ no_xml_query_rewrite */ 
     xmlquery(
     'copy $d := . 
     modify (
      for $i in $d/a 
      return replace value of node $i/b with ''nana'' 
     ) 
     return $d' 
     passing t.xml_data 
     returning content 
     ) as updated_doc 
from (select xmlType('<a> 
     <b>Something to change here</b> 
     <c>Here is some narrative containing weirdly escaped \&lt;tags>\&lt;/tags> </c> 
    </a>') as xml_data from dual) t 
; 

Также при использовании xmlTransform я получить тот же результат. Я пытался использовать

disable-output-escaping="yes" 

Но это сделал наоборот - он незаменяемые в & лт; :

select XMLTransform(
    xmlType('<a> 
     <b>Something to change here</b> 
     <c>Here is some narrative containing weirdly escaped \&lt;tags>\&lt;/tags> </c> 
    </a>'), 
    XMLType(
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
     <xsl:template match="https://stackoverflow.com/a/b"> 
       <b> 
       <xsl:value-of select="text()"/> 
       </b> 
     </xsl:template> 

     <xsl:template match="https://stackoverflow.com/a/c"> 
       <c> 
       <xsl:value-of select="text()" disable-output-escaping="yes"/> 
       </c> 
     </xsl:template> 
</xsl:stylesheet>')) 
from dual; 

вернулся:

<a> 
    <b>NewValue</b> 
    <c>Here is some narrative containing weirdly escaped <tags></tags> </c> 
</a> 

Есть предложения? Две вещи, которые вы должны знать:

  1. Я не могу изменить первоначальный формат - он приходит ко мне на этом пути и мне нужно, чтобы сохранить его.
  2. Исходное сообщение настолько велико, что изменение сообщение в строку и обратно (для использования регулярных выражений как обходное решение) будет не делать трюк.
+0

Риск звучать глупо: почему это проблема для вас, что персонажи избегают? Никакой соответствующий XML-процессор не может жаловаться, что '>' представляется как '>' - действительно, если вы фактически не сравниваете строки, образующие разметку, нет никакого способа сказать разницу. Есть ли вероятность, что это просто не проблема? –

+0

К сожалению, нам нужно уменьшить изменения до минимума, так как этот xml получается из внешней системы и используется для согласования с этой системой. Если есть изменения, они жалуются, что сообщение отличается и говорят, что они никогда не отправляли ничего подобного. Причина в том, что я, очевидно, уже меняю сообщение, но это значит, что повторное опосредствование ошибки, которая создала изменение в первую очередь (сохранение таких xml-адресов не является проблемой, обновление - это). –

+0

Являются ли ваши исходные данные фактически 'XMLType' или это' CLOB'? В последнем случае вы можете уйти с помощью 'DBMS_LOB', чтобы изменить значение без штрафа (хотя это будет нелегко). –

ответ

1

корень вашей проблемы, кажется, что ваше исходное значение XML для узла C не является действительным XML, если он содержит > в пределах значения вместо &gt;, а не внутри CDATA section (также What does <![CDATA[]]> in XML mean?).

Строковое значение:

Here is some narrative containing weirdly escaped &lt;tags>\&lt;/tags>

в формате XML должно быть действительно

<c>Here is some narrative containing weirdly escaped &amp;lt;tags&gt;\&amp;lt;/tags&gt;</c>

ИЛИ

<c><![CDATA[Here is some narrative containing weirdly escaped &lt;tags>\&lt;/tags>]]></c>

Я либо запросить исправление XML в источнике, либо реализовать какой-либо метод для санировки самих входов, например, обертывание значений узла <c> в <![CDATA[]]>.Если вам нужно сохранить точное исходное значение, а сообщения большие, то самое лучшее, что я могу придумать, это копирование дубликатов экземпляров с исходным значением в виде строки и сохранение «дезинфицированного» значения в виде типа данных XML.

+1

XML хорошо сформирован. В стандарте XML указывается, что '&' и '<' будут экранированы, но он позволяет unescaped '>', за исключением последовательности ']]>' (во избежание путаницы с CDATA). Обратная косая черта - это escape-символ Oracle, поэтому содержимое элемента действительно (без каких-либо исключений). Вот какой-то рассказ, содержащий странно экранированный '. –

+1

Хотя я согласен с тем, что это должно быть в CDATA, это не так, и, как сказал Джероен, поскольку он ничего не нарушает, нет достаточных оснований для изменения ввода - это часть большой и сложной системы, и такое изменение будет иметь для синхронизации и передачи данных в несколько нисходящих систем. Не очень правдоподобно. Сохранение исходной строки на стороне является лишь обходным решением, и, хотя оно подходит, это не чистое решение. Что меня мешает, так это то, что я не могу найти способ просто обновить этот xml без Oracle, оказывая мне услугу, пытаясь помочь там, где это не предполагается. ;) –

+0

Я не понимал, что '>' был действителен в XML, так что спасибо, я узнал что-то новое сегодня! @MichalLozinski - это ваши данные в таблице, которая хранится с использованием типа данных XMLType? Похоже, что функция «updateXML» устарела, поэтому вы можете попробовать использовать некоторые из предложений, упомянутых в этой статье https://docs.oracle.com/database/121/ADXDB/app_depr_upd.htm # ADXDB6060 (проверьте разделы «Пример реляционной эквивалентности объекта C-7 выражения UPDATEXML» и «Таблица C-1 Миграция запросов XML-обновления XML-запросов к обновлению XQuery») – BateTech

0

В итоге нам удалось это сделать с помощью java. By:

  1. чтение XML как CLOB
  2. модифицирующих его в Java
  3. хранить его обратно в базу данных, используя java.sql.Connection (по какой-то причине, если бы мы использовали JdbcTemplate, он жаловался о приведении в Лонг, который был признаком того, что строка была более 4000 байт (речь о чистых ошибок, все оклик Oracle) и использование CLOB типа не очень помощи. Я предполагаю, что это совсем другая история, хотя)

При хранении данных оракул не выполняет никаких магов, только обновления, как правило, изменяют escape-символы.

Возможно, это не ответ для всех, но хороший обходной путь, если вы наткнетесь на ту же проблему, что и мы.

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