title: Using Oracle XMLElement in complex PL/SQL
body: <p>Using Oracle 10gR2, I need to produce something like the following pseudo-example from data stored in standard relational tables.</p>
  
  <pre><code>&lt;product&gt;
    &lt;productName&gt;p1&lt;/productName&gt;
    &lt;productNumber&gt;100&lt;/productNumber&gt;
    &lt;productObsoletes&gt;
       &lt;obsoletedProduct label=1&gt;50&lt;/obsoletedProduct&gt;
       &lt;obsoletedProduct label=2&gt;55&lt;/obsoletedProduct&gt;
    &lt;/productObsoletes&gt;
  &lt;/product&gt;
  </code></pre>
  
  <p>The problem is, I need to do decision making using the rows which contain the data.  My database (which I inherited) is poorly designed and the logic needed to decide upon a rows inclusion is complex.  Unfortunately, redesigning the database is not an option.  I'm vastly simplifying the logic here, so it's not a case where a simple join or where clause can be used.  There's a complex hierarchy to the data, and the data format definition.</p>
  
  <p>In psuedo code, the way-oversimplified decision would look something like:</p>
  
  <pre><code>BEGIN
     --select our basic attributes
  
       select XMLEMENT("product",XMLELEMENT("productName",name),XMLELEMENT("productNumber",product_number))
  into xml_output from products where product_number = 100;
  
     --now process our obsolete rows
     select XMLELEMENT("productObsoletes") into xml_output from dual;
     FOR c_row in (select * from product_obsoletes where id=100)
     LOOP
         IF c_row.display = 'YES' THEN
          select XMLELEMENT("obsoletedProduct", XMLATTRIBUTES(c_row.label as "label"), c_row.obsoleted_product_id) into xml_output from dual;
         ELSE
            CONTINUE;
         END IF;
     END LOOP;
  END;
  </code></pre>
  
  <p>Obviously though, this doesn't work.  First, XMLElement always puts a closing tag on, so unless you can formulate a single select statement containing all of your elements, it's not going to work. Second, in this example, I'd be overwriting the previous XMLELEMENT output.  I can't concatenate, because XMLELEMENT has already closed the tag.</p>
  
  <p>The only solution I can think of at this point is to select the various XMLElement pieces I need into different VARCHARS and then use string manipulation functions to find the right spot to insert the various pieces.  Ugly with a capital-U.</p>
  
  <p>Is there another solution?  Is there perhaps a way to prevent XMELEMENT from closing the tag so that you can you use complex looping logic?  Or another Oracle construct which would allow me to achieve my goal of building up this XML without having to use a single select statement?</p>
  
  <p>My path of last resort would be to do the XML generation from another language such as Java or Perl where I could simply fetch the data and then do my complex processing and XML generation there.  However, I'd much prefer just to have a SQL function which would return the correct XML as a string, so if it's possible to do it in PL/SQL, that'd be my preferred route.</p>