Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 UpdateXml()  [new]
Cotton
Member

Откуда: Киев
Сообщений: 202
Есть таблица table_name в которой есть столбец column_name xml-типа. Нужно пройтись по этому столбцу и в каждом xml-документе поменять значения конкретных тэгов на какую-то константу. Т.е. если мы имели <OD_CM_ID>100900</OD_CM_ID>, то нужно получить <OD_CM_ID>200900</OD_CM_ID> - сделать смещение на 100000.
Смотрел здесь, но как-то там уж слишком запутано.
--------
Любовь и боль
Покой и бой
Я как любой
Несу с собой
29 июн 06, 17:56    [2827512]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862
Может можно и одним запросом, или так:
declare
  xml  XMLType :=
    XMLType('<ROOT><OD_CM_ID>1</OD_CM_ID><OD_CM_ID>2</OD_CM_ID><OD_CM_ID>3</OD_CM_ID></ROOT>');
begin
  for i in (
    select rownum rw, extract(value(t), 'OD_CM_ID/text()').getNumberVal() id
    from table(XMLSequence(xml.extract('/ROOT/OD_CM_ID'))) t
  ) loop
    select updateXml(
               xml
             , '/ROOT/OD_CM_ID['||i.rw||']'
             , XMLType('<OD_CM_ID>'||to_char(i.id+100000)||'</OD_CM_ID>')
           )
    into xml
    from dual;
  end loop;
  dbms_output.put_line(xml.getStringVal());
end;
/
29 июн 06, 18:17    [2827611]     Ответить | Цитировать Сообщить модератору
Между сообщениями интервал более 1 года.
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
Denis Popov
Может можно и одним запросом, или так:
declare
  xml  XMLType :=
    XMLType('<ROOT><OD_CM_ID>1</OD_CM_ID><OD_CM_ID>2</OD_CM_ID><OD_CM_ID>3</OD_CM_ID></ROOT>');
begin
  for i in (
    select rownum rw, extract(value(t), 'OD_CM_ID/text()').getNumberVal() id
    from table(XMLSequence(xml.extract('/ROOT/OD_CM_ID'))) t
  ) loop
    select updateXml(
               xml
             , '/ROOT/OD_CM_ID['||i.rw||']'
             , XMLType('<OD_CM_ID>'||to_char(i.id+100000)||'</OD_CM_ID>')
           )
    into xml
    from dual;
  end loop;
  dbms_output.put_line(xml.getStringVal());
end;
/


А что делать если не цифровые значения а к примеру varchar? .getStringVal() ...a что же делать с rownum ? действительно интересный пример!

Сообщение было отредактировано: 1 июн 09, 13:44
1 июн 09, 13:04    [7251037]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862
SS69
А что делать если не цифровые значения а к примеру varchar? .getStringVal() ...a что же делать с rownum ?

Можно через XSL:

with src as (
  select XmlType(
'<ROOT>
  <OD_CM_ID>1<X/></OD_CM_ID>
  <OD_CM_ID>2<Y/></OD_CM_ID>
  <OD_CM_ID>3<X/></OD_CM_ID>
</ROOT>') xml
  from DUAL
)
select XmlTransform (
           src.xml
         , XmlType (
'<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="*">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/ROOT/OD_CM_ID">
    <xsl:copy>
      <xsl:variable name="id" select="."/>
      Value:<xsl:value-of select="$id"/>
      <xsl:apply-templates select=".//*"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>'
           )
       ).extract('*') result
from src;

Т.е. ловишь значение каждого элемента /ROOT/OD_CM_ID и делай с ним что хочешь.
1 июн 09, 14:12    [7251384]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
Denis Popov

Можно через XSL:
with src as (
  select XmlType(
'<ROOT>
  <OD_CM_ID>1<X/></OD_CM_ID>
 .....
           )
       ).extract('*') result
from src;

Т.е. ловишь значение каждого элемента /ROOT/OD_CM_ID и делай с ним что хочешь.

Я немного туплю но мои значения то что мне нужны в $id , как мне их словить я просто или не понял или не понял.... как мне увязать с апдейтом?
with src as (
  select XmlType(
'<ROOT>
  <OD_CM_ID><date>первый</date></OD_CM_ID>
  <OD_CM_ID><date>второй</date></OD_CM_ID>
  <OD_CM_ID><date>третий</date></OD_CM_ID>
</ROOT>') xml
  from DUAL
)
select XmlTransform (
           src.xml
         , XmlType (
'<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="*">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
   
  <xsl:template match="/ROOT/OD_CM_ID/date">
    <xsl:copy>
      <xsl:variable name="id" select="."/>
      <xsl:value-of select="$id"/>
      <xsl:apply-templates select=".//*"/>
    </xsl:copy>
  </xsl:template>
  


</xsl:stylesheet>'
           )
       ).extract('/') result
from src;
Заранее благодарен за помощь всем откликнувшимся.
P.S. можно даже линку на литературу кинуть что с xSL и апдейтом
1 июн 09, 18:03    [7252967]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862

SS69 wrote at 01.06.2009 19:03:

> Я немного туплю но мои значения то что мне нужны в $id , как мне их
> словить я просто или не понял или не понял.... как мне увязать с апдейтом?

Как ты их хочешь поменять, что есть на входе и что должно получиться на выходе, приведи в качестве
примера?

Posted via ActualForum NNTP Server 1.4

1 июн 09, 18:09    [7252996]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
Denis Popov, Вот в первоначальном виде
На входе clob c xml данными.=>[чёрный ящик]=>На выходе clob с xml данными(другими).

[чёрный ящик]:мы берём значения из тега и апдейтим его значениями из таблицы.

Вроде бы всё просто но 4-сутки не могу найти варианта.
1 июн 09, 18:59    [7253200]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862
SS69
Denis Popov, Вот в первоначальном виде
На входе clob c xml данными.=>[чёрный ящик]=>На выходе clob с xml данными(другими).

[чёрный ящик]:мы берём значения из тега и апдейтим его значениями из таблицы.

Теоретически, если идти через XSL, то из значений в таблицах можно формировать куски xsl-шаблона с условиями замены: если .. то .. (<xsl:if>), и так по всем значениям из таблицы, после чего примерить преобразование к исходному документу. Тут по крайней мере легко составить все остальное в неприкосновенности, хотя может есть и более красивые решения.

Сообщение было отредактировано: 2 июн 09, 01:22
2 июн 09, 01:21    [7253956]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
Denis Popov, более красивое решение...на мой взгляд вот...только опять же апдейт просто отказывается работать!
create or replace function rus_to_eng(pRus in varchar2) return clob is  
  Result  clob;
  i sys_refcursor;
  xml          clob;
  xml2         clob;
begin
select distinct app_obj_source_1 into xml
      from app_objects
     where app_obj_name = pRus;
open i for
select extractvalue(value(li), '/cell/data') str
    from table(XMLSequence(extract(xmltype(xml),'/book//sheets/sheet/cells/cell'))) li;
    loop
    fetch i into xml2;
    exit when i%notfound;
    select updatexml(xml,'/book//sheets/sheet/cells/cell/data[text()='||xml2||']', xmltype('<data>'||(select eng from transl where rus=xml2)||'</data>')
    into xml
    from dual;
    end loop;
 result:=xml;
return(Result);
end rus_to_eng;

Подскажите где ляп? Ругается что типы не те возвращаются какие нужно!
2 июн 09, 11:58    [7255078]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
create or replace function rus_to_eng(pRus in varchar2) return clob is
  Result  clob;
  i sys_refcursor;
  xml          clob;
  xml2         clob;
  tmpxml  XMLType;
begin
select distinct app_obj_source_1 into xml
      from app_objects
     where app_obj_name = pRus;
open i for
select extractvalue(value(li), '/cell/data') str
    from table(XMLSequence(extract(xmltype(xml),'/book//sheets/sheet/cells/cell'))) li;
    loop
    fetch i into xml2;
    exit when i%notfound;
    select updatexml(xmltype(xml),'/book//sheets/sheet/cells/cell/data['||xml2||']',rus_to_en(xml2))
    into tmpxml
    from dual;
    end loop;
 result:=tmpxml.getclobval();
return(Result);
end rus_to_eng;
Вот как бы окончательный вариант! всё работает! за исключением ругается на разбор xml во время updatexml ругаясь на data['||xml2||']'
2 июн 09, 12:21    [7255188]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862

SS69 wrote at 02.06.2009 13:21:

> Вот как бы окончательный вариант! всё работает! за исключением ругается
> на разбор xml во время updatexml ругаясь на data['||xml2||']'


Навскидку: попробуй объявить xml2 как varchar2, если хватит. Но в твоем варианте по-моему на каждый
вызов updateXml будет строиться новый DOM-объект, сколько займет это по времени и ресурсам?

Posted via ActualForum NNTP Server 1.4

2 июн 09, 12:35    [7255283]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
Denis Popov, дело даже не в формате ,вернувшись к исходному, он просто отказывается апдейтить такое чувство что он не реагирует на то что внутри апдейта задан параметр или мне нужно existnode использовать?
declare
  i    sys_refcursor;
  xml2 varchar2(3000);
  xml  XMLType := XMLType('<ROOT><OD_CM_ID>раз</OD_CM_ID><OD_CM_ID>два</OD_CM_ID><OD_CM_ID>три</OD_CM_ID></ROOT>');
begin
  open i for
    select extractvalue(value(li), '/OD_CM_ID') str
      from table(XMLSequence(extract(xml, '/ROOT/OD_CM_ID'))) li;
  loop
    fetch i
      into xml2;
    exit when i%notfound;
dbms_output.put_line(xml2);
    select updatexml(xml,
                     '/ROOT/OD_CM_ID[' || xml2 || ']',
                     XMLType('<OD_CM_ID>' || xml || '</OD_CM_ID>'))
      into xml
      from dual;
  end loop;
  dbms_output.put_line(xml.getStringVal());
end;
/
2 июн 09, 13:15    [7255569]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
VBR
Member

Откуда:
Сообщений: 79
Попробуйте такой вариант.

DECLARE
  v_parser  xmlparser.Parser;
  v_doc     xmldom.DOMDocument;
  v_nl      xmldom.DOMNodeList;
  v_n       xmldom.DOMNode;   

 v_clob clob;           
  
 BEGIN
  v_clob:= '<ROOT><OD_CM_ID>1</OD_CM_ID><OD_CM_ID>2</OD_CM_ID><OD_CM_ID>3</OD_CM_ID></ROOT>';

  v_parser := dbms_xmlparser.newParser;
  dbms_xmlparser.parseClob(v_parser,v_clob);
  v_doc := dbms_xmlparser.getDocument(v_parser);
  v_nl :=xslprocessor.selectNodes(dbms_xmldom.makeNode(v_doc),'//OD_CM_ID/text()');
  
  FOR i IN 0 .. xmldom.getLength(v_nl)-1 LOOP
   v_n := xmldom.Item(v_nl,i);
   xmldom.setNodeValue(v_n,to_char(45+i)); 
  end loop;  
  dbms_xmldom.writeToClob(v_doc, v_clob);
  xmldom.freeDocument(v_doc);
  dbms_xmlparser.freeParser(v_parser);
  dbms_output.put_line(v_clob);
END;
2 июн 09, 13:21    [7255611]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
Вернулись к вопросу как работает updatexml
Ниже приведенный фрагмент с exixstnode ясно показывает что d select update мы не попадаем! Почему?
.....
exit when i%notfound;
    if xml.existsnode('/ROOT/OD_CM_ID['||xml2||']') = 1 THEN
    dbms_output.put_line(xml2);
    select updatexml(xml,
.....
2 июн 09, 13:23    [7255625]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
VBR, опять же только для чисел отличный вариант! Когда надо все числа увеличить к примеру на 45 тому обязательно подойдёт. А тут ситуэйшн другой надо не по порядку заменять а по точному значению...если есть такое то поменять на такое же тока инглиш
2 июн 09, 13:33    [7255687]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862
SS69
Вернулись к вопросу как работает updatexml
Ниже приведенный фрагмент с exixstnode ясно показывает что d select update мы не попадаем! Почему?

Ты про это?
declare
  cr_xml  sys_refcursor;
  v_value varchar2(3000);
  xml     XMLType := XMLType(
'<ROOT>
  <OD_CM_ID>раз</OD_CM_ID>
  <OD_CM_ID>два</OD_CM_ID>
  <OD_CM_ID>три</OD_CM_ID>
</ROOT>'
);
begin
  open cr_xml for
    select extractValue(value(li), '/OD_CM_ID') str
    from table(XMLSequence(extract(xml, '/ROOT/OD_CM_ID'))) li;
  loop
    fetch cr_xml into v_value;
    exit when cr_xml%notfound;
dbms_output.put_line(v_value);
    select updateXml (
               xml
             , '/ROOT/OD_CM_ID[text()="'||v_value||'"]/text()'
             , v_value||'_XXX'
           )
    into xml
    from DUAL;
  end loop;
  dbms_output.put_line(xml.extract('*').getStringVal());
  close cr_xml;
end;
/


Сообщение было отредактировано: 2 июн 09, 13:57
2 июн 09, 13:51    [7255822]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
Denis Popov, огромное спасибо что помогал. Уже нашёл причину - загвоздка оказалась в "'||v_value||'" я не поставил двойные кавычки =) Всё я надеюсь материал кому нибудь ещё поможет! Всем спасибо! Denis Popov-требуй за модераторство премию!!! Ещё раз всем продуктивных успехов.
2 июн 09, 14:22    [7256052]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
VBR
Member

Откуда:
Сообщений: 79
Наверное я не понял что надо

DECLARE
  v_parser  xmlparser.Parser;
  v_doc     xmldom.DOMDocument;
  v_nl      xmldom.DOMNodeList;
  v_n       xmldom.DOMNode;   
  v_clob clob;           
   v_temp varchar2(200); 
 BEGIN
  v_clob:= '<ROOT><OD_CM_ID>1</OD_CM_ID><OD_CM_ID>2</OD_CM_ID><OD_CM_ID>3</OD_CM_ID></ROOT>';

  v_parser := dbms_xmlparser.newParser;
  dbms_xmlparser.parseClob(v_parser,v_clob);
  v_doc := dbms_xmlparser.getDocument(v_parser);
  v_nl :=xslprocessor.selectNodes(dbms_xmldom.makeNode(v_doc),'//OD_CM_ID/text()');
  
  FOR i IN 0 .. xmldom.getLength(v_nl)-1 LOOP
   v_n := xmldom.Item(v_nl,i);
   v_temp:=xmldom.getNodeValue(v_n);
  begin 
  --  Возможно выгоднее загнать в коллекцию, потом один раз select и уже потом setnodevalue
   select min(eng) into v_temp from spr_engrus t where t.rus=v_temp;
    exception when others then null; -- оставить прежний, если не нашел
  end; 
-- или if(v_temp=old_val) then    xmldom.setNodeValue(v_n,new_val);
   xmldom.setNodeValue(v_n,v_temp);
  end loop;  

  dbms_xmldom.writeToClob(v_doc, v_clob);
  xmldom.freeDocument(v_doc);
  dbms_xmlparser.freeParser(v_parser);
  dbms_output.put_line(v_clob);
END; 
2 июн 09, 15:16    [7256404]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
VBR, классно! Только меня просто Oracle выкидывает с интереснийшими ошибками если немного поправить код!

 select en -- это clob а внутри xml
    into v_clob 
    from slovar; 
  

Ошибки ORA-03113: end-of-file on communication channel
ORA-03114 not connected to oracle
2 июн 09, 18:06    [7257646]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
Alexander_111
Member [заблокирован]

Откуда: Москва
Сообщений: 290
SS69,

вот нет предела изыскам.
Я повторяю. Зачем создавать XML структуры в процедурах. Нужно создать VIEW на теги XML- type столбца и все. Заделайтесь update <имя VIEW> set <атрибут VIEW>=<значение> сколько угодно...
Чего проще... Еще проиндексируйте теги XML - type столбца, чтобы все летало, а не парьтесь изысками...
2 июн 09, 18:45    [7257865]     Ответить | Цитировать Сообщить модератору
 Re: UpdateXml()  [new]
SS69
Member

Откуда:
Сообщений: 39
Как я понимаю
Alexander_111
Нужно создать VIEW на теги XML- type столбца и все.

Нужно ещё создать для начала shema самой структуры моего xml фала и зарегить в БД, а потом уже view....

VBR, парсинг работает на вылет базы и всех узверей с неё т.к. xml получается очень большим.

Denis Popov, время 120 секунд сервер 99% всей оперативы.

....стоит задуматся над вариантом Alexander_111.
3 июн 09, 11:07    [7259536]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить