Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 89 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
89
Dung lượng
549,17 KB
Nội dung
• You can execute the procedure from the SQL*Plus command line using the EXEC command as follows: EXEC QuotesForStocksInPortfolio(101) After successful execution, you can see the resulting contents of the web page buffer by issuing: EXEC OWA_UTIL.SHOWPAGE If you have previously issued SET SERVEROUTPUT ON from SQL*Plus, you will see the contents of the page buffer in your SQL*Plus command console. After requesting the page buffer, the OWA routines flush the buffer. • If you are using one of the web servers listed earlier on a computer named yourserver, and you have properly registered a virtual path location named yourpath to point to the database schema where you created the previous PL/SQL procedure, you can request the page through a web browser (or any program capable of making an HTTP request) using the URL: http://yourserver/yourpath/QuotesForStocksInPortfolio?id=101 10.1.4 Formatting Database Data in XML Using PL/SQL The process of generating dynamic XML documents in PL/SQL based on query results is identical to the procedure used for generating HTML: 1. Identify the set of data to publish in XML by executing one or more SQL queries. 2. Loop over the resulting data. 3. Output the data, surrounded by appropriate XML tags. 10.1.4.1 Returning an XML stock quote datagram When you want to format database query results in XML instead of HTML, the programming techniques remain the same; only the tags around the data change. By making slight modifications to Example 10.7, we can generate dynamic XML datagrams filled with stock quotes in no time. Studying Example 10.8, you'll notice a few obvious changes: • We're explicitly setting the MIME type of the returned document to text/xml using the MIME_HEADER routine in the built-in OWA_UTIL package. • We're outputting an XML declaration instead of an <HTML> tag as the very first text in the page. • The tags used to mark up the data have meaningful element names that reflect the structure of the query result's information, unlike the fixed set of HTML tags, like <TD>, which signify visual presentation of the data. Example 10.8. Procedure to Return XML Stock Quote Datagram CREATE PROCEDURE XMLQuotesForStocksInPortfolio( id NUMBER ) IS Select all stocks for the user with id passed in CURSOR c_QuotesForUserid( cp_Userid NUMBER ) IS SELECT q.symbol, q.price, q.change FROM quotes q, portfolio_stocks ps WHERE q.symbol = ps.symbol AND ps.owner = cp_Userid; BEGIN OWA_UTIL.MIME_HEADER('text/xml'); HTP.P('<?xml version="1.0"?>'); HTP.P('<Quotes>'); FOR curQuote IN c_QuotesForUserid( id ) LOOP HTP.P('<Quote>'); HTP.P('<Symbol>' ||curQuote.symbol||'</Symbol>'); HTP.P('<Price>' ||curQuote.price ||'</Price>'); HTP.P('<Change>' ||curQuote.change||'</Change>'); HTP.P('</Quote>'); END LOOP; HTP.P('</Quotes>'); END XMLQuotesForStocksInPortfolio; We have to set the MIME type of the result to text/xml so that a requesting user agent can make an informed decision about how it wants to handle the XML document we're returning. Depending on the web server you're using, you may also have to register text/xml as one of the valid MIME types the server recognizes. Web developers producing static pages with graphics and text never need to think about MIME types, since most modern web servers automatically set the MIME type of requested web resources like .html and .gif files based on their file extension. In addition, many developers producing dynamic HTML pages don't have to think about MIME types, since most web servers default the MIME type of dynamically generated pages to text/html. With dynamically generated XML, however, we must take care to set the MIME type manually; otherwise, your data pages will most likely be handled like HTML when they get to their destination. If you begin to write lots of PL/SQL stored procedures that format XML, you'll quickly get tired of printing out the tags manually. Just as the HTP and HTF packages offer routines for more reliably creating common HTML tags, we can write a quick helper routine to assist with the formatting of opening and closing tags for our XML. Example 10.9 creates a PL/SQL package named xmlhelper by providing its PACKAGE specification and companion PACKAGE BODY, defining the implementation of the routines in the package. Example 10.9. Helper Package to Simplify XML Creation CREATE OR REPLACE PACKAGE xmlhelper IS PROCEDURE prolog; PROCEDURE startTag( elementName VARCHAR2 ); PROCEDURE tag( elementName VARCHAR2, content VARCHAR2 := NULL); PROCEDURE endTag( elementName VARCHAR2 ); END xmlhelper; CREATE OR REPLACE PACKAGE BODY xmlhelper IS PROCEDURE prolog IS BEGIN OWA_UTIL.MIME_HEADER('text/xml'); HTP.P('<?xml version="1.0"?>'); END prolog; PROCEDURE startTag( elementName VARCHAR2 ) IS BEGIN HTP.P('<'||elementName||'>'); END startTag; PROCEDURE tag( elementName VARCHAR2, content VARCHAR2 := NULL) IS BEGIN HTP.P( '<'||elementName||'>' ||content || '</'||elementName||'>'); END tag; PROCEDURE endTag( elementName VARCHAR2 ) IS BEGIN HTP.P('</'||elementName||'>'); END endTag; END xmlhelper; The prolog routine encapsulates the setting of the text/xml MIME type as well as the printing of the XML declaration. prolog should always be called before calling any of the other routines to generate tags for the content of the page. The startTag and endTag routines do what their names imply, while the tag routines combine these to print the start tag, some text content, and the end tag in one command. If we were to rewrite Example 10.8 using our new xmlhelper package, our code would look like Example 10.10. Example 10.10. Improved Procedure Returning XML Stock Quotes CREATE PROCEDURE XMLQuotesForStocksInPortfolio( id NUMBER ) IS Select all stocks for the user with id passed in CURSOR c_QuotesForUserid( cp_Userid NUMBER ) IS SELECT q.symbol, q.price, q.change FROM quotes q, portfolio_stocks ps WHERE q.symbol = ps.symbol AND ps.owner = cp_Userid; BEGIN xmlhelper.prolog; xmlhelper.startTag('Quotes'); FOR curQuote IN c_QuotesForUserid( id ) LOOP xmlhelper.startTag('Quote'); xmlhelper.tag('Symbol', curQuote.symbol); xmlhelper.tag('Price', curQuote.price); xmlhelper.tag('Change', curQuote.change); xmlhelper.endTag('Quote'); END LOOP; xmlhelper.endTag('Quotes'); END XMLQuotesForStocksInPortfolio; As before with the HTML-producing stored procedure, we can test the output of our XML-producing stored procedure using: EXEC XmlQuotesForStocksInPortfolio(101) followed by: EXEC OWA_UTIL.SHOWPAGE from the SQL*Plus command line, or by browsing the URL: http://yourserver/yourpath/XmlQuotesForStocksInPortfolio?id=101 10.2 Automatic XML Generation with DBXML We could certainly continue with PL/SQL examples, demonstrating how to write stored procedures to: • Format the query results from multiple SQL statements into a single resulting XML page • Generically process any SQL query, using the built-in DBMS_SQL package, generating appropriate XML tags for their column names • Automatically search for additional information in related tables by checking the database dictionary views for metadata about foreign key and primary key constraints But luckily, we don't have to write this code ourselves, since Oracle provides all this functionality in the freely downloadable set of XML Utilities for PL/SQL called PLSXML which includes lots of demos and source code (see http://technet.oracle.com/tech/xml/info/plsxml/xml4plsql.htm). The readme.html file in the readme directory in the PLSXML distribution provides setup instructions. 10.2.1 Letting DBXML Do the Work for You The heart of the PLSXML suite of utilities is a PL/SQL package called DBXML. The package offers a key procedure named Query that accepts a SQL query to be processed and automatically produces the XML output in the OWA page buffer. As Example 10.11 illustrates, it is practically no work at all to use Dbxml.Query. Passing any query to it as a string causes the appropriately formatted XML document representing its query results to be sent to the HTP page buffer. Example 10.11. Automatically Producing Stock Quote XML with DBXML CREATE PROCEDURE StockQuotesDbxmlBasic( id NUMBER ) IS BEGIN Dbxml.Query('SELECT q.symbol as Symbol, q.price as Price, q.change as Change FROM quotes q, portfolio_stocks ps WHERE q.symbol = ps.symbol AND ps.owner = ' || id); END; With a single line of PLSQL, any query can be published in XML over the Web! By default, for a query whose leading table name is TABLENAME in the FROM clause, Dbxml.Query creates: • A <TABLENAMELIST> element to wrap the entire set of rows • A <TABLENAME> element to wrap each row of data • The database column names as element names for each column's data The default output from Dbxml.Query for a simple query like Example 10.11 looks like this: <?xml version="1.0" ?> <! Oracle DBXML Version 1.1.10 Query Results at 20-JUN-2000 22:10:57 > <! SELECT SYMBOL,PRICE,CHANGE FROM quotes q, portfolio_stocks ps WHERE q.symbol = ps.symbol AND ps.owner = 101 > <QLIST> <Q> <SYMBOL>GE</SYMBOL> <PRICE>103.5</PRICE> <CHANGE>.8</CHANGE> </Q> <Q> <SYMBOL>ORCL</SYMBOL> <PRICE>27.33</PRICE> <CHANGE>3.4</CHANGE> </Q> </QLIST> By providing values for some of Dbxml.Query 's optional parameters, you can control certain aspects of its automatic XML generation. A simple example of this is to substitute the default tags with custom values, as in Example 10.12. Example 10.12. XML Stock Portfolio Using DBXML CREATE PROCEDURE StockQuotesDbxml( id NUMBER ) IS BEGIN Dbxml.Query('SELECT q.symbol as Symbol, q.price as Price, q.change as Change FROM quotes q, portfolio_stocks ps WHERE q.symbol = ps.symbol AND ps.owner = ' || id, theDocElement => 'PORTFOLIO', tableElement => 'QUOTE' ); END; This produces the requested effect on the output: <?xml version="1.0" ?> <! Oracle DBXML Version 1.1.11 Query Results at 05-JUL-1999 18:58:12 > <! SELECT SYMBOL,PRICE,CHANGE FROM quotes q, portfolio_stocks ps WHERE q.symbol = ps.symbol AND ps.owner = 101 > <PORTFOLIO> <QUOTE> <SYMBOL>GE</SYMBOL> <PRICE>103.5</PRICE> <CHANGE>.8</CHANGE> </QUOTE> <QUOTE> <SYMBOL>ORCL</SYMBOL> <PRICE>27.33</PRICE> <CHANGE>3.4</CHANGE> </QUOTE> </PORTFOLIO> After looking in the next section at using Dbxml.Query to work with information for multiple tables in a single request, we'll cover all of the options available to control Dbxml.Query 's output. 10.2.2 Returning XML Information for Multiple Tables One of the key values of XML is its ability to elegantly represent trees of related information. For example, if you imagine an XML document representing a patient's medical history, you would assume such a document should include information about the patient, the patient's medical visits with various doctors at one or more medical facilities, as well as other details. In a relational database like Oracle, the information for each of these different kinds of business entities is stored in separate tables, and relationships between the entities are captured by referential constraints between tables. As an example, Figure 10.1 shows a simple schema for a Medical Visit Tracking application. Figure 10.1. Sample schema to track medical visits Depending on the information needs of the moment, the tables in Figure 10.1 provide the foundation for many different XML documents: • A <PATIENT> profile, with related information about the patient's <VISIT>s and which <DOCTOR>s the patient saw at what <FACILITY>s • A <DOCTOR> profile, with related information about the list of the doctor's <VISIT>s and <PATIENT>s visited • A <STATE> profile, with related information about the list of <CITY>s in the state, and what medical <FACILITY>s exist in each city The list could clearly go on. The key point is that the tables in a relational database, together with the referential constraints among them, have the potential to represent many different XML documents, depending on your desired point of view. Dbxml.Query offers a built-in capability to "walk" relationships and include data tables that are related to the table you provide as the starting point. By providing Dbxml.Query an initial query based on the PATIENT table, for example, it will include information about related medical visits from the VISIT table. The process is recursive, so information from the VISIT table will be supplemented by related details from the FACILITY table where the visit took place as well as information from the DOCTOR table about the doctor who saw the patient. You can provide a parameter upon invoking Dbxml.Query to indicate which tables you wish to exclude from the set of details to control how far the "walking" goes. Let's look at a couple of simple examples using this feature of Dbxml.Query and the tables from Figure 10.1. Example 10.13 shows an example of a patient profile datagram. Example 10.13. Multi-Table Patient Profile with DBXML CREATE PROCEDURE PatientProfile( id NUMBER ) IS BEGIN Dbxml.Query('SELECT * FROM patient WHERE id = '|| id , includeDetails => 'Y', detailExclusionList => 'FACILITY'); END; Executing the PatientProfile procedure through the Oracle Web Agent produces the XML document in Example 10.14. Example 10.14. Nested DBXML Query Results for the Patient Table <?xml version="1.0" ?> <! Oracle DBXML Version 1.1.10 Query Results at 20-JUN-2000 22:27:22 > <! SELECT * FROM patient WHERE id = 2099344 > <PATIENTLIST> <PATIENT> <ID>2099344</ID> <FIRSTNAME>Laurel</FIRSTNAME> <LASTNAME>Birch</LASTNAME> <VISITLIST> <VISIT> <ID>198554</ID> [...]... exploit the facilities of the XML SQL Utility, you can use the OracleXML command-line program or you can use the OracleXMLQuery class in your own custom programs To use the command-line program, ensure that the Java archive files for the XML SQL Utility, the Oracle XML Parser version 2, and the Oracle JDBC driver are in your CLASSPATH, and invoke the command: java OracleXML to see the command-line options... the output tags Extending our XMLForResultSet class to offer generic support for these additional requirements would be a non-trivial task Luckily, we don't have to build this code ourselves since Oracle provides the XML SQL Utility for Java, which includes the OracleXMLQuery component that automates the entire job 11.3.1 Using OracleXMLQuery to Do the Work for You OracleXMLQuery is a utility class that... command-line options The first argument can either be the keyword getXML to exercise the functionality of retrieving XML from SQL, or putXML to store an XML file into a table or view We'll see more of the OracleXML utility in Chapter 12 To use the XML SQL Utility's functionality in your own programs, you simply: 1 Create an instance of OracleXMLQuery, passing a Connection and either a SQL query String or... Parameters String sql = request.getParameter("sql"); // Create SQL-to -XML Handler OracleXMLQuery q = new OracleXMLQuery(cn, sql); // Generate XML results and write to output out.println(q.getXMLString( )); cn.close( ); %> Requesting the URL: http://xmlapps/ShowQuery.jsp?dtd=y&sql=select+*+from+doctor+where+id='bblatt' produces the results: < ?xml version="1.0"?> XML datagrams for any SQL statement passed in, optionally including a dynamically generated DTD Example 11.15 ShowQuery.jsp Returns XML for Any Query 'Y', detailExclusionList => 'COUNTRY,DOCTOR,VISIT'); END; The results of this stored procedure appear in Example 10. 16 Example 10. 16 Nested DBXML Query Results for the State Table < ?xml version="1.0" ?> Oracle DBXML Version 1.1.10... demonstrates how to use XMLForResultSet in a simple program We've rewritten Example 11.1 to call the XMLForResultSet.print() method in place of all the hand-coded XML tag generation When XML utilities are driven off runtime metadata, one line of code can be very effective Example 11.3 Using XMLForResultSet.print( ) to Produce XML import java.sql.*; import java.io.*; public class StockQuotesXml { public static... override any default XML- generation settings 3 Retrieve the XML results by calling either of the following methods: o getXMLString() to read the query results as an XML document in a string o getXMLDOM() to return the query results as a DOM Document When using getXMLString() you can optionally include a document type definition reflecting the structure of the query results by calling getXMLString(true)... what we need for real Oracle XML applications For these to be effective, we need to serve application information in XML over the Web 11.2.1 Serving Datagrams Using Java Servlets Leveraging the work we've already done in the StockQuotesXml class from Example 11.3, we can produce dynamic stock quote datagrams for web delivery by extending HttpServlet in a class called StockQuotesXmlServlet and performing... oracle. xml. parser.v2.*; import org.w3c.dom.NodeList; public class TestTimegram{ static XMLDocument theTimegram = null; public static void main(String arg[]) throws Exception { // Construct a parser DOMParser dp = new DOMParser( ); // Parse the XML document returned by CurrentDateXML.jsp dp.parse("http://xmlapps/ch11/CurrentDateXML.jsp"); // Get the XML Document theTimegram = dp.getDocument( ); // Use XPath expression . the Oracle Web Agent produces the XML document in Example 10.14. Example 10.14. Nested DBXML Query Results for the Patient Table < ?xml version="1.0" ?> <! Oracle DBXML. stored procedure appear in Example 10. 16. Example 10. 16. Nested DBXML Query Results for the State Table < ?xml version="1.0" ?> <! Oracle DBXML Version 1.1.10 Query Results at. http://technet .oracle. com/tech /xml/ info/plsxml /xml4 plsql.htm). The readme.html file in the readme directory in the PLSXML distribution provides setup instructions. 10.2.1 Letting DBXML Do the Work for