【问题标题】:Convert XMLTYPE to VARCHAR将 XMLTYPE 转换为 VARCHAR
【发布时间】:2016-12-17 19:37:59
【问题描述】:

我正在尝试使用 httpRequest 在插入时发送 xmltype 表内容,为此我必须将其转换为 varchar 以在 POST 中传递。

这是我的插入:

    Insert into CC.MOVIE (SYS_NC_ROWINFO$) values ('<movie>
      <id>217530</id>
      <title>Midnight Limited</title>
      <originalTitle>Midnight Limited</originalTitle>
      <release_date>1940-03-20</release_date>
      <status>3</status>
      <vote_average>0</vote_average>
      <vote_count>0</vote_count>
      <runtime>0</runtime>
      <certification/>
      <budget>61</budget>
      <tagline>DEATH RIDES THE RAILS!                                                                                                                                                        </tagline>
      <genres>
        <genre>
          <idGenre>12</idGenre>
        </genre>
        <genre>
          <idGenre>28</idGenre>
        </genre>
        <genre>
          <idGenre>80</idGenre>
        </genre>
      </genres>
      <actors>
        <actor>
          <idActor>32218</idActor>
          <characterName>Prof. Van Dillon</characterName>
        </actor>
        <actor>
          <idActor>87545</idActor>
          <characterName>Joan Marshall</characterName>
        </actor>
        <actor>
          <idActor>90336</idActor>
          <characterName>Val Lennon</characterName>
        </actor>
        <actor>
          <idActor>120708</idActor>
          <characterName>Capt. Harrigan</characterName>
        </actor>
      </actors>
      <directors>
        <director>
          <idDirector>120796</idDirector>
        </director>
      </directors>
    </movie>
    ');

还有我的触发器:

create or replace TRIGGER movie_insert

      AFTER INSERT ON MOVIE
      FOR EACH ROW
      DECLARE
      doc XMLType;
      req utl_http.req;
      res utl_http.resp;
      url varchar2(4000) := 'http://10.0.2.2:8088/VerifActeur/VerifActeur';
      --name varchar2(4000);
      buffer varchar2(5000); 
      BEGIN
    SELECT 
      EXTRACTVALUE(:new.object_value, '/movie/text()')
    INTO buffer
    FROM DUAL;

    --Select CAST(:new.object_value AS VARCHAR2(5000)) into buffer from dual;
      -- buffer := :new.object_value.getStringVal();
        --doc := :new.sys_nc_rowinfo$;
      --buffer:= :new.object_value.extract('/movie/text()').getStringVal();
      dbms_output.put_line(buffer);

        req := utl_http.begin_request(url, 'POST');
        --utl_http.set_header(req, 'user-agent', 'mozilla/4.0'); 
        utl_http.set_header(req, 'content-type', 'text/xml'); 
        utl_http.set_header(req, 'Content-Length', length(buffer));

        utl_http.write_text(req, buffer);

        res := utl_http.get_response(req);
        -- process the response from the HTTP call
        begin
          loop
            utl_http.read_line(res, buffer);
            dbms_output.put_line(buffer);
          end loop;
          utl_http.end_response(res);
        exception
          when utl_http.end_of_body 
          then
            utl_http.end_response(res);
        end;
        utl_http.end_request(req); 
      END;

但是提取值输出什么也不显示,在这种情况下请求不是凹痕(可能是因为长度什么都不返回)。并且其他方法正在返回异常。

【问题讨论】:

    标签: sql oracle plsql xmltype


    【解决方案1】:

    您的movie 节点不包含任何文本,它仅包含子节点;所以 extractvalue 返回 null 是正确的。顺便说一句,该功能已从 11g 中弃用。您的插入和触发器当前正在查看不同的列,这可能没有帮助,但这可能是问题中的错误,而不是您的实际代码。

    您可以使用XMLSerialize 将 XMLType 值转换为字符串、varchar 或(如果该值对于该数据类型而言太大)CLOB,类似于:

    SELECT XMLSerialize(DOCUMENT :new.object_value AS VARCHAR2(4000) NO INDENT)
    INTO buffer
    FROM dual;
    

    您还没有说您使用的是哪个版本的 Oracle。在 12c 之前,SQL 上下文意味着您限制为 4000 个字符,但您的缓冲区被声明为 5000。使用 no indent 可能会去除足够的空白,这不会成为问题,但您可能必须改用 CLOB。

    使用一个虚拟表,并将触发器插入到同一个 XMLType 列中进行查询(为什么要使用数据字典表中的列名?希望您实际上没有向数据字典添加触发器?)并注释掉现在的 HTTP 位,产生:

    Table MOVIE created.
    
    Trigger MOVIE_INSERT compiled
    
    <movie><id>217530</id><title>Midnight Limited</title><originalTitle>Midnight Limited</originalTitle><release_date>1940-03-20</release_date><status>3</status><vote_average>0</vote_average><vote_count>0</vote_count><runtime>0</runtime><certification/><budget>61</budget><tagline>DEATH RIDES THE RAILS!                                                                                                                                                        </tagline><genres><genre><idGenre>12</idGenre></genre><genre><idGenre>28</idGenre></genre><genre><idGenre>80</idGenre></genre></genres><actors><actor><idActor>32218</idActor><characterName>Prof. Van Dillon</characterName></actor><actor><idActor>87545</idActor><characterName>Joan Marshall</characterName></actor><actor><idActor>90336</idActor><characterName>Val Lennon</characterName></actor><actor><idActor>120708</idActor><characterName>Capt. Harrigan</characterName></actor></actors><directors><director><idDirector>120796</idDirector></director></directors></movie>
    
    
    1 row inserted.
    

    在触发器中执行此操作看起来很尴尬,即使 dbms_output 仅用于调试。例如,如果 http 调用失败会发生什么 - 是否仍应存储新行,或者是否将异常过滤到调用者并按照您的需要/预期回滚?不清楚插入的人会发生什么。将插入和 http 调用放到存储过程中可能会更健壮,这样逻辑就在一起并且易于查看,而不是通过触发器依赖副作用。然后阻止对表的直接访问(无论如何都要插入)并且只允许调用包装过程。只是一个想法......

    【讨论】:

    • 我尝试按照您的建议使用 XMLSerialize,但出现此错误:ORA- 30991: "cannot use DOM to add special attribute to schema-based parent"
    • 来自触发器中的那个查询?我不确定如何。不幸的是,我目前无法对此进行测试,也无法重新创建该错误。您使用的是哪个版本的 Oracle?嗯,你正在将 XML 插入到SYS_NC_ROWINFO$,那么objct_value 是从哪里来的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-07
    • 2011-12-11
    • 2021-05-22
    • 2013-02-28
    • 2010-09-05
    • 2021-04-25
    • 1970-01-01
    相关资源
    最近更新 更多