Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 20 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
20
Dung lượng
159,06 KB
Nội dung
There is only one method left to document—the writeError. This is a simple util- ity method for writing out any errors. Since it is the last method, this code snippet also contains the closing brace for the class: void writeError(String mesg) { System.out.println(“An error occurred”); System.out.println(mesg); } } Now you can put this code to use. In Chapter 7, you used a table called newsletter to study the XML handling actions. In this example, you use the command line tool to input some rows into the table. Here is the XSQL that will exist on the Web server side; the filename is insert-to-newsletter-plain.xsql: <?xml version=”1.0”?> <page connection=”momnpup” xmlns:xsql=”urn:oracle-xsql”> <xsql:insert-request table=”newsletter”/> </page> As discussed in Chapter 7, the xsql:insert-request action assumes that there is an XML document in the canonical rowset schema contained in the HTTP request. Our SimpleServicesApp will load a file and embed the XML in the request. Here is what the file looks like, which we’ll call newsletter.xml: <?xml version = ‘1.0’?> <ROWSET> <ROW num=”1”> <NAME>test name2</NAME> <EMAIL>test1@momnpup.com</EMAIL> </ROW> <ROW num=”2”> <NAME>test name2</NAME> <EMAIL>test2@momnpup.com</EMAIL> </ROW> </ROWSET> You invoke the SimpleServicesApp as follows: prompt> java SimpleServicesApp http://localhost/xsql/momnpup/insert- request.xsql newsletter.xml When the request arrives at the HTTP server, it looks like this: POST /xsql/momnpup/insert-request.xsql HTTP/1.1 Content-Type: text/xml User-Agent: Java1.3.1_02 Host: localhost Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive 460 Chapter 16 Content-length: 226 <?xml version = ‘1.0’?> <ROWSET> <ROW num=”1”> <NAME>test name2</NAME> <EMAIL>test1@momnpup.com</EMAIL> </ROW> <ROW num=”2”> <NAME>test name2</NAME> <EMAIL>test2@momnpup.com</EMAIL> </ROW> </ROWSET> There are two differences between this and a standard post. First, the Content -Type is set to text/xml. The second difference is more obvious. Instead of having a list of name-value pairs in the body of the request, you have the XML document con- tained in newsletter.xml. XSQL processes the data into the database and then returns the result. In this case, the result looks like this: Opening http://localhost/xsql/momnpup/insert-request.xsql <?xml version = ‘1.0’?> <page> <xsql-status action=”xsql:insert-request” rows=”2”/> </page> The result isn’t transformed, so you get a plain xsql-status message. Likewise, you had to have your input in the plain-vanilla canonical format as well. If you are forced to deal with the XML like this, your Web services wouldn’t be very flexible. As with the application development discussed in Chapter 14, the secret lies with XSLT. The remaining sections focus on how you can use XSLT to create truly independent Web services. XML-to-XML Transformations In most examples given in earlier chapters, the target of the transformation is HTML. The HTTP client makes a request and the XSQL application transforms XML to HTML by using XSLT. In this section, you’ll see how to transform into XML, which is required by most Web services consumers. Your stylesheet starts with XML in the canonical Ora- cle format and then transforms that into another XML document. Consequently, the Web services consumer takes the outputted XML document. This discussion looks at the specifics on how to perform XML transformations. The XSLT stylesheet is referenced in the XSQL page exactly as it is in other cases. The key syntax difference is to use the xsl:output element so that XML is sent to the consumer. Web Services with XSQL 461 <xsl:output method=”xml”/> This should be an immediate child of the root element of your stylesheet. Depending on the requirements of your Web services consumer, you may also need to use some of the other attributes of the xsl:output element. The most commonly used are encoding, doctype-public, and doctype-system. All of these are covered in Chapter 14, so here we’ll just look at them in terms of how they apply to Web services. The encoding attribute controls what character encoding the XSLT processor will use when it sends the output to the Web services consumer. If your Web services con- sumer expects a particular character encoding, then you’ll need to set it in the xsl:out- put element. Otherwise, you may encounter some very difficult-to-solve errors. The doctype-public and doctype-system attributes concern DTDs. You haven’t seen DTDs actually used yet because Web browsers don’t need them. But in Web services, you will usually have some kind of schema definition. The consumer may just assume that it always receives valid XML, but more likely it wants to have the schema referenced in the document. The doctype-public and doctype-system attributes take care of this when you use the DTD schema language. If you need to have a DTD in your document that looks like the following, <!DOCTYPE mydef PUBLIC “-//SOME_DEF//DTD MYDEF 1.1//EN” “http://www.momnpup/DTD/my_def.xml”> you can create it by using the following xsl:output element: <xsl:output method=”xml” doctype-public=”-//SOME_DEF//DTD MYDEF 1.1//EN” doctype-system=” http://momnpup.com/DTD/my_def.xml”> If you use an XML-based schema language, such as W3C’s XML Schema, you can set the schema as you would any other XML data. In the case of XML Schema, you would include only the following as static text in your stylesheet: <root xmlns=”http://momnpup/ns/my_namespace” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://momnpup.com/xsd file:my_def.xsd”> From here, your stylesheet transformations will be just like the transformations that you’ve been doing all along. Instead of conforming to HTML, you conform to the rules of the Web consumer’s expected schema. This usually means that you make a lot of use of the xsl:element and xsl:attribute elements.You’ll start with the simple XSQL tricks; then you’ll look at the XSLT techniques. For this example, imagine that the Web services consumer expects a document like the following when it requests a list of products: <PRODUCTS> <PRODUCT> 462 Chapter 16 <PRODUCT_ID>3</PRODUCT_ID> <PRODUCT_NAME>Step Ladder</PRODUCT_NAME> <PRODUCT_PRICE>30.00</PRODUCT_PRICE> </PRODUCT> <PRODUCT> <PRODUCT_ID>4</PRODUCT_ID> <PRODUCT_NAME>Coffee Mug</PRODUCT_NAME> <PRODUCT_PRICE>20.00</PRODUCT_PRICE> </PRODUCT> </PRODUCTS> Here’s the query that gets the data: SELECT id, name, price FROM product Unfortunately, this doesn’t solve the problem, because the consumer expects prod- uct_id, product_name, and product_price elements. This can be easily addressed just by aliasing the column names in SQL so that you get the following XSQL page: <xsql:query connection=”momnpup” xmlns:xsql=”urn:oracle-xsql”> SELECT id AS product_id, name AS product_name, price AS product_price FROM product </xsql:query> This gets you closer—you end up with the following output: <ROWSET> - <ROW num=”1”> <PRODUCT_ID>3</PRODUCT_ID> <PRODUCT_NAME>Step Ladder</PRODUCT_NAME> <PRODUCT_PRICE>30.00</PRODUCT_PRICE> </ROW> - <ROW num=”2”> <PRODUCT_ID>4</PRODUCT_ID> <PRODUCT_NAME>Coffee Mug </PRODUCT_NAME> <PRODUCT_PRICE>20.00</PRODUCT_PRICE> </ROW> Now you can use the rowset-element and row-element attributes in your XSQL to rename the rowset and row elements: <xsql:query connection=”momnpup” xmlns:xsql=”urn:oracle-xsql” Web Services with XSQL 463 rowset-element=”PRODUCTS” row-element=”PRODUCT”> SELECT id AS product_id, name AS product_name, price AS product_price FROM product </xsql:query> This gives the consumer the following output, which is almost perfect: <PRODUCTS> - <PRODUCT num=”1”> <PRODUCT_ID>3</PRODUCT_ID> <PRODUCT_NAME>Step Ladder</PRODUCT_NAME> <PRODUCT_PRICE>30.00</PRODUCT_PRICE> </PRODUCT> - <PRODUCT num=”2”> <PRODUCT_ID>4</PRODUCT_ID> <PRODUCT_NAME>Coffee Mug</PRODUCT_NAME> <PRODUCT_PRICE>20.00</PRODUCT_PRICE> </PRODUCT> There is only one problem with our output. Each product has an attribute num, but the schema requires that it be count. This can be fixed by setting the id-attribute in the xsql:query as follows: <xsql:query connection=”momnpup” xmlns:xsql=”urn:oracle-xsql” rowset-element=”PRODUCTS” row-element=”PRODUCT” id-attribute=”count”> SELECT id AS product_id, name AS product_name, price AS product_price FROM product </xsql:query> For this simple example, the output is valid according to the schema, and you didn’t need XSLT at all. The next example requires XSLT. You need to output data that looks like this: <CATEGORY_LIST> <CATEGORY id=”7”> <NAME>Bathroom</NAME> <DESCRIPTION>Keep clean and healthy with these products</DESCRIPTION> <PRODUCT id=”10”> <NAME>Band-aids</NAME> <PRICE>5.31</PRICE> </PRODUCT> 464 Chapter 16 <PRODUCT id=”3”> <NAME>Tweezers</NAME> <PRICE>3.99</PRICE> </PRODUCT> </CATEGORY> <CATEGORY id=”8”> <NAME>Outdoor Clothing Men</NAME> <DESCRIPTION>Functional wear for the outdoorsmen</DESCRIPTION> <PRODUCT id=”11”> <NAME>Jeans</NAME> <PRICE>25.99</PRICE> </PRODUCT> </CATEGORY> This query is immediately out of scope of the XSQL tricks, because the id is the product id, not the row number. Also, it has a tree format that isn’t reproducible with XSQL. You can get all of the data with a single query by using cursors, but XSQL will put a “_ROW” suffix at the end of the cursor field. Here’s the XSQL page that will get the data: <?xml version=”1.0” encoding=”UTF-8”?> <xsql:query connection=”momnpup” xmlns:xsql=”urn:oracle-xsql” rowset-element=”PRODUCT_CATEGORIES” row-element=”CATEGORY”> SELECT pc.id, pc.name,pc.description, CURSOR(SELECT p.id,p.name,p.price FROM product p,prod_cat_joiner pcj WHERE p.id=pcj.product_id AND pc.id=pcj.product_cat_id) AS products FROM product_category pc ORDER BY pc.name </xsql:query> The output of this XSQL is as follows: <PRODUCT_CATEGORIES> <CATEGORY num=”1”> <ID>7</ID> <NAME>Bathroom</NAME> <DESCRIPTION>Keep clean and healthy with these products</DESCRIPTION> <PRODUCTS> <PRODUCTS_ROW num=”1”> <ID>10</ID> <NAME>Band-aids</NAME> Web Services with XSQL 465 <PRICE>5.31</PRICE> </PRODUCTS_ROW> </PRODUCTS> </CATEGORY> </PRODUCT_CATEGORIES> The XSLT faces a couple of challenges. You have to rename several of the element names, and you have to add the id attribute for the CATEGORY and PRODUCT ele- ments. It would be possible to create a highly verbose stylesheet that has a template for every single element. For this example, the stylesheet is much more concise. It assumes that all the elements are in the correct order, and it makes use of the xsl:element, xsl:attribute, and xsl:copy-of to translate the structure. The header informa- tion and the top-level template is as follows: <?xml version = ‘1.0’?> <xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0”> <xsl:output method=”xml”/> <xsl:template match=”/PRODUCT_CATEGORIES”> <CATEGORY_LIST> <xsl:apply-templates select=”CATEGORY”/> </CATEGORY_LIST> </xsl:template> The top-level template makes CATEGORY_LIST the root and then defers to the CATEGORY template to do the rest of the work. Of course, you could change the rowset-element to CATEGORY_LIST in the XSQL page. However, the preceding example illustrates an important point—if the element name is essentially static, you can always just name it in the template like this. If you don’t mind verbosity, you can just structure the entire document with static text like this. But for this example, you can use a cleaner approach, as follows: <xsl:template match=”CATEGORY”> <xsl:element name=”CATEGORY”> <xsl:attribute name=”id”><xsl:value-of select=”ID”/></xsl:attribute> <xsl:copy-of select=”*[name()!=’ID’ and name()!=’PRODUCTS’]”/> <xsl:apply-templates select=”PRODUCTS/PRODUCTS_ROW”/> </xsl:element> </xsl:template> The preceding template overcomes two challenges. First, it sets the id element as an attribute of the category element. Incidentally, you can use the id-attribute and id-attribute-column attributes of xsql:query to accomplish the same thing. You would set id-attribute to “id” and set id-attribute-column to “ID”. Regardless, sooner or later you will probably have to use the preceding template. If you need to set more than one attribute, you’ll have to use this template. Second, it copies all the values of the children into the output, except for PRODUCTS and ID. You can use the xsl:copy-of element if the element name in the XSQL 466 Chapter 16 datagram is the same as the one desired and if you want to keep all the attributes (if there are any) and child nodes. In our case, the name in the datagram is right. This name is more than coincidental. You can control the names of elements in the result set by aliasing them to what you want. You can also control whether the element has child nodes. When you work at this level of a datagram, you will not have child nodes unless you reference a cursor, collection, or object. The PRODUCTS element does represent a cursor, so it is handled in the following template: <xsl:template match=”PRODUCTS/PRODUCTS_ROW”> <xsl:element name=”PRODUCT”> <xsl:attribute name=”id”><xsl:value-of select=”ID”/></xsl:attribute> <xsl:copy-of select=”*[name()!=’ID’]”/> </xsl:element> </xsl:template> </xsl:stylesheet> This template handles the problem with the PRODUCTS and PRODUCTS_ROW ele- ments. You don’t need them, though you do want their children. This template creates a new element for each of the children and effectively skips two levels in the XSQL datagram. As before, an attribute is set by using a child value; the other elements are then copied. The id element isn’t needed, so it is ignored in the xsl:copy-of ele- ment. This template is the last in the stylesheet, so the closing tag is included in the code snippet. The two examples show a few ways how you can easily convert the XML datagram to the correct output. You can use the XSQL tricks described here to get the output close to if not entirely correct, and then you can greatly simplify your XSLT stylesheets by making use of xsl:element, xsl:attribute, and xsl:copy-of. XML Handling Actions The previous discussion showed how to create the XML that is sent to a Web services consumer. Just as important as that is dealing with the XML that is sent to XSQL as part of a Web services consumer’s request. XSQL has three actions that handle the posted XML: insert-request, update-request, and delete-request. These actions are covered in detail in Chapters 5 and 7. For each of these actions, you can specify a single stylesheet used to interpret the posted XML. The XML must be transformed into the canonical row format as dis- cussed before. All of the XML handling actions use the same posted XML, but each can transform it with different stylesheets. This means that a single posted XML document can be used by multiple XML handling actions. Each action can use only the data that it needs out of the posted document. The real work is transforming the data with XSLT as described in this chapter. The same XSLT techniques can apply but aren’t necessarily as available. When you push the data into the database, you can’t count on aliasing. The element names must be the same as they are in the table. Thus, it is more likely that you will need a verbose stylesheet that specifically changes each element’s name and that the xsl:copy-of technique shown in this chapter won’t be as useful. Web Services with XSQL 467 Moving On In this chapter you have learned about how Web services can work with XSQL. This and the previous chapter showed you that XSQL can be very useful beyond traditional Web pages. From the next chapter on, you’ll start learning how to extend the XSQL framework with Java. The next chapter covers how to use XSQL from inside your applications. In Chapter 18, you’ll see how to write your own custom action handlers and serializers. 468 Chapter 16 469 So far, you’ve used XSQL as a framework. You encapsulate SQL and PL/SQL in an XSQL file, reference an XSLT stylesheet, and produce a result. In the next chapter, you’ll see how to extend the framework by writing your own custom action handlers. This chapter looks at a completely different approach—how to use XSQL inside your programs. Oracle provides a Java API for XSQL. You can instantiate an XSQLPageRequest object and then run it against the database. It will return the result as XML. At that point, you can transform it by using a stylesheet. This gives you some advantages. For example, you can keep the SQL outside of your programming logic. If you need to change the SQL, you can do so in an external file instead of having to recompile code. Now you have an XML document that can be used by other parts of your application. Instead of having to process a result set and create your own XML document, this is all done automatically. Also, you can transform the document programmatically by using a stylesheet. This chapter looks at how to use XSQL programmatically, starting with a sample program. You will get an idea of what you can do with the APIs. Then the XSQLPageRequest class and XSLTPageProcessor class are studied in detail. The last two discussions look at the DOM and SAX APIs provided by Oracle, which give you two ways of processing XML documents. XSQL Beyond Web Browsing CHAPTER 17 [...]... import import import import import import oracle. xml.xsql.XSQLRequest; oracle. xml.parser.v2.XMLPrintDriver; oracle. xml.parser.v2.XMLDocument; oracle. xml.parser.v2.XMLDocumentFragment; oracle. xml.xsql.XSQLStylesheetProcessor; oracle. xml.parser.v2.XSLProcessor; oracle. xml.parser.v2.XSLStylesheet; oracle. xml.parser.v2.DOMParser; oracle. xml.parser.v2.XMLNode; oracle. xml.jaxp.JXDocumentBuilderFactory; import... Beyond Web Browsing DOM Interface Hierarchy org.w3c.dom.Node Oracle DOM Implementation oracle. xml.parser.v2.XMLNode IMPLEMENTS org.w3c.dom.Element IMPLEMENTS oracle. xml.parser.v2.XMLElement org.w3c.dom.Document IMPLEMENTS oracle. xml.parser.v2.XMLDocument org.w3c.dom.Text IMPLEMENTS oracle. xml.parser.v2.XMLText org.w3c.dom.CDataSectino IMPLEMENTS oracle. xml.parser.v2.XMLCData Figure 17.1 DOM interfaces... classes of DOM The Oracle DOM API is a set of classes There is a class that implements each of the interfaces in DOM For instance, XMLDocument implements the document interface Since the document interface extends the node interface, XMLDocument also implements the node interface All the Oracle classes are prefixed with XML and live in the oracle. xml.parser.v2 package When using the Oracle DOM API, you... have your SAX parser consume that stream 475 476 Chapter 17 Oracle DOM API Oracle provides an implementation of DOM It is completely compatible with W3C DOM It offers some advantages beyond DOM, including XPath integration and a simple way to import nodes from one document to another If you have other code that uses DOM, any coding you do in Oracle DOM should be compatible For instance, if a method expects... instance, if a method expects a DOM object such as Node, you can always pass it an instance of Oracle s implementation, XMLNode Thus, you can take advantage of the Oracle- provided extensions to DOM while your system still remains fully compatible with DOM This section looks first at the DOM model and then how Oracle extends it DOM is a set of Java interfaces that extend one another Since Java is a single... the most useful aspects of the Oracle DOM is the integration with XPath The XMLNode class has two sets of methods that will take XPath expressions as arguments—selectNodes() and valueOf() The selectNodes methods return lists of nodes, while valueOf retrieves text values This greatly simplifies the process of navigating a DOM tree There are a variety of other methods in the Oracle DOM API that are worth... XMLDocument also implements the node interface All the Oracle classes are prefixed with XML and live in the oracle. xml.parser.v2 package When using the Oracle DOM API, you can cast between the DOM type and its Oracle equivalent The reverse is also true In addition, you can also cast to any of the superclasses of the DOM equivalent, as illustrated by the following code: Document w3cDoc=req.processToXML(); XMLDocument... for the various XSQL pages You’ll be making more use of these classes in the next chapter as you write action handlers This section acts as a guide to the XSQLRequest class and the other classes in the oracle. xml.xsql package You’ll find the complete javadoc for all of the classes in the XSQL distribution When using XSQL programmatically, you’ll have to use the XSQLResult class In the previous example,... At this point in the program, the resulting XML datagram has been printed to the screen There is a lot more you can do with it if you like You can take the xsqlDoc object and work with it through the Oracle XML DOM APIs You can add, remove, and modify nodes, and you can even merge nodes with other documents You’ll see some of this functionality in the next chapter The last step for the code is to apply . follows: import oracle. xml.xsql.XSQLRequest; import oracle. xml.parser.v2.XMLPrintDriver; import oracle. xml.parser.v2.XMLDocument; import oracle. xml.parser.v2.XMLDocumentFragment; import oracle. xml.xsql.XSQLStylesheetProcessor; import. oracle. xml.xsql.XSQLStylesheetProcessor; import oracle. xml.parser.v2.XSLProcessor; import oracle. xml.parser.v2.XSLStylesheet; import oracle. xml.parser.v2.DOMParser; import oracle. xml.parser.v2.XMLNode; import oracle. xml.jaxp.JXDocumentBuilderFactory; import. Interface Hierarchy Oracle DOM Implementation oracle. xml.parser.v2.XMLNode IMPLEMENTS org.w3c.dom.Element oracle. xml.parser.v2.XMLElement IMPLEMENTS org.w3c.dom.Document oracle. xml.parser.v2.XMLDocument IMPLEMENTS org.w3c.dom.Text