2016-03-23 72 views
0

下面是一个简单的从Oracle 11g数据库(在这个简单示例中使用双表)中获取数据到平面文件的示例。XML输出文件的格式不正确,我不确定为什么

我期待在文件中的格式如下。

<message> 
    <production> 
    <prodCategoryType>test type 1</prodCategoryType> 
    <prodStatusType>prod status 1</prodStatusType> 
    </production> 
</message> 
<message> 
<production> 
    <prodCategoryType>test type 2</prodCategoryType> 
    <prodStatusType>prod status 2</prodStatusType> 
</production> 
</message> 

,但我发现下面的代替,这​​似乎缺少启动消息,生产标签,并把一个奇怪的上>在中间。

<message> 
    <production> 
    <prodCategoryType>test type 1</prodCategoryType> 
    <prodStatusType>prod status 1</prodStatusType> 
    </production> 
</message> 
on> 
    <prodCategoryType>test type 2</prodCategoryType> 
    <prodStatusType>prod status 2</prodStatusType> 
    </production> 
</message> 

我做错了什么?

DECLARE 

l_file UTL_FILE.FILE_TYPE; 
l_clob CLOB; 
l_buffer VARCHAR2(32767); 
l_amount BINARY_INTEGER := 32767; 
l_pos  INTEGER := 1; 
l_extract_dir    CONSTANT dba_directories.directory_name%TYPE:= 'REPORTS_OUT_DIR'; -- \\data2\data\download\d7prdv1\prsrepreports 


l_xmltype XMLTYPE; 
l_domdoc dbms_xmldom.DOMDocument; 
l_root_node dbms_xmldom.DOMNode;  

l_message_node   dbms_xmldom.DOMNode; 

l_production_element dbms_xmldom.DOMElement; 
l_production_node  dbms_xmldom.DOMNode; 

-- production XML elements, node, text 
l_prod_element     dbms_xmldom.DOMElement;  
l_prod_node   dbms_xmldom.DOMNode; 
l_prod_t_node   dbms_xmldom.DOMNode; 
l_prod_text   dbms_xmldom.DOMText; 
-- production XML elements, node, text, node 

CURSOR c_production 
IS SELECT 'test type 1',   as prodCategoryType 
      'prod status 1'   as prodStatusType 
    from dual    
    UNION 
    SELECT 'test type 2',   as prodCategoryType 
      'prod status 2'   as prodStatusType 
    from dual; 

BEGIN 
UTL_FILE.FCLOSE_ALL; -- make sure all file handles are closed for session 
l_file := UTL_FILE.fopen(l_extract_dir , 'Sample2.dat', 'w', 32767); 

-- Create an empty XML document 
    l_domdoc := dbms_xmldom.newDomDocument; 

-- Create a root node 
l_root_node := dbms_xmldom.makeNode(l_domdoc); 

-- Create a message root node 
l_message_node := dbms_xmldom.appendChild(l_root_node, dbms_xmldom.makeNode(dbms_xmldom.createElement(l_domdoc, 'message')) 
            );  

FOR production_rec in c_production LOOP 

    l_production_element := dbms_xmldom.createElement(l_domdoc, 'production'); 
    l_production_node := dbms_xmldom.appendChild(l_message_node,dbms_xmldom.makeNode(l_production_element)); 

    -- prodCategoryType 
    l_prod_element := dbms_xmldom.createElement(l_domdoc, 'prodCategoryType'); 
    l_prod_node := dbms_xmldom.appendChild(l_production_node,dbms_xmldom.makeNode(l_prod_element)); 
    l_prod_text := dbms_xmldom.createTextNode(l_domdoc, production_rec.prodCategoryType); 
    l_prod_t_node := dbms_xmldom.appendChild(l_prod_node,dbms_xmldom.makeNode(l_prod_text)); 

    -- prodStatusType 
    l_prod_element := dbms_xmldom.createElement(l_domdoc, 'prodStatusType'); 
    l_prod_node := dbms_xmldom.appendChild(l_production_node,dbms_xmldom.makeNode(l_prod_element)); 
    l_prod_text := dbms_xmldom.createTextNode(l_domdoc, production_rec.prodStatusType); 
    l_prod_t_node := dbms_xmldom.appendChild(l_prod_node,dbms_xmldom.makeNode(l_prod_text)); 


     l_xmltype := dbms_xmldom.getXmlType(l_domdoc); 
     l_clob  := l_xmltype.getClobVal; 
     DBMS_LOB.read (l_clob, l_amount, l_pos, l_buffer); 
     UTL_FILE.put(l_file, l_buffer); 
     l_pos := l_pos + l_amount; 

    END LOOP; 

dbms_xmldom.freeDocument(l_domdoc); 
UTL_FILE.fclose(l_file); 

END; 

回答

0

你真的犯了两件错事。那么,三个。由于没有根节点,因此您期望的输出不是有效的XML;从早期的问题你可能只是略过了(AV-XML?),但它不清楚。

虽然您实际生成的内容是有效的,但不是您期望的格式。在环路l_xmltype第一次迭代后包含:

<message> 
    <production> 
    <prodCategoryType>test type 1</prodCategoryType> 
    <prodStatusType>prod status 1</prodStatusType> 
    </production> 
</message> 

......这就是你所期望的。但第二循环后,第二条生产节点同样的信息节点下插入,所以你必须:

<message> 
    <production> 
    <prodCategoryType>test type 1</prodCategoryType> 
    <prodStatusType>prod status 1</prodStatusType> 
    </production> 
    <production> 
    <prodCategoryType>test type 2</prodCategoryType> 
    <prodStatusType>prod status 2</prodStatusType> 
    </production> 
</message> 

当你第一次写出来给你留下l_pos坐在收盘</message>结束的文件标签,并且您假设您具有您期望看到的结构,这意味着在下一个循环中,下一个字符将成为第二个<message>标签的开头。但是由于(单个)结束标记已经移动,所以l_pos实际上现在处于新插入的第二个<production>标记的中间。读取从该点开始,因此从该开始标签的on>部分开始。

您应该做的主要事情是将XML从输出生成到文件。有一个循环建立起来的DOM,你在做什么,然后一个单独的循环之后写XML输出到文件:

... 
    l_prod_t_node := dbms_xmldom.appendChild(l_prod_node,dbms_xmldom.makeNode(l_prod_text)); 

    /* Remove all existing conversion/writing from the first loop 
     l_xmltype := dbms_xmldom.getXmlType(l_domdoc); 
     l_clob  := l_xmltype.getClobVal; 
     DBMS_LOB.read (l_clob, l_amount, l_pos, l_buffer); 
     UTL_FILE.put(l_file, l_buffer); 
     l_pos := l_pos + l_amount; 
    */ 
    END LOOP; 

    WHILE l_pos <= dbms_lob.getlength(l_clob) LOOP 
    DBMS_LOB.read (l_clob, l_amount, l_pos, l_buffer); 
    UTL_FILE.put(l_file, l_buffer); 
    UTL_FILE.fflush(l_file); 
    l_pos := l_pos + l_amount; 
    END LOOP; 
    UTL_FILE.fclose(l_file); 
END; 
/

这样您就可以反映你产生实际的XML文件。然后你可以调整这个世代以拥有一个不同的根节点,并在循环内部添加消息和生产节点。只需将l_message_node := ...行移动到第一个循环中,即可获得问题中的结构。

+0

这真是太棒了Alex Poole。 –

+0

刚刚运行它,现在唯一的问题是它是我认为最大的clob和打印不再和部分打印一半标签见下文。 TEST1 TEST_1_TEST TEST1

+0

所以我想我需要写/追加到归档生产节点节点的每一次迭代。 –