将XMLTYPE转换为VARCHAR

时间:2016-12-17 19:37:59

标签: sql oracle plsql xmltype

我尝试使用httpRequest在insert上发送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;

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

1 个答案:

答案 0 :(得分: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调用放入存储过程可能更加健壮,因此逻辑在一起并且易于查看,而不是通过触发器依赖副作用。然后阻止对表的直接访问(无论如何为插入)并且只允许调用包装程序。只是一个想法...