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
141,53 KB
Nội dung
name, and price while the xsql:include-owa action is used to return the XML doc- ument using the get_product_xml procedure used earlier. <?xml version=”1.0”?> <prod-details connection=”momnpup” xmlns:xsql=”urn:oracle-xsql”> <xsql:include-xsql href=”cat-nav.xsql”/> <xsql:query rowset-element=”PRODUCT-SET” row-element=”DETAILS” product_id=”0” bind-params=”product_id”> SELECT id,name,price FROM product WHERE id=? </xsql:query> <xsql:include-owa product_id=”0” bind-params=”product_id” > get_product_xml(?); </xsql:include-owa> </prod-details> The last page for the public interface is the search results page. It uses the query developed earlier and, like our other subordinate pages, includes the navigational ele- ment on the left. <?xml version=”1.0”?> <prod-search connection=”momnpup” xmlns:xsql=”urn:oracle-xsql”> <xsql:include-xsql href=”cat-nav.xsql”/> <xsql:query rowset-element=”PRODUCT_SEARCH” row-element=”PRODUCT”> SELECT id, name, a.doc.extract(‘/product/summary/text()’).getStringVal() AS summary FROM product a WHERE contains(doc,’{@search_terms}’)>0 ORDER BY contains(doc,’{@search_terms}’) </xsql:query> </prod-search> You have three XSQL pages for the price editor interface. The first displays the nec- essary information in response to a lookup: <?xml version=”1.0”?> <prod-search connection=”momnpup” xmlns:xsql=”urn:oracle-xsql”> <xsql:query rowset-element=”PRICE_EDITOR_SEARCH” row-element=”PRICE_EDITOR_PRODUCT”> SELECT p.name AS product_name, pc.name AS product_cat_name, p.price FROM product p, prod_cat_joiner pcj, product_category pc WHERE p.id=pcj.product_id AND pcj.product_cat_id=pc.id 400 Chapter 14 AND p.name like ‘%{@terms}%’ </xsql:query> </prod-search> Your second XSQL page is very similar to the product details page. The information for this page will be used to fill the values for the fields of a particular editor. <xsql:query connection=”momnpup” xmlns:xsql=”urn:oracle-xsql” rowset-element=”PRODUCT-SET” row-element=”DETAILS” product_id=”0” bind-params=”product_id”> SELECT id,name,price FROM product WHERE id=? </xsql:query> The last page to create is the page that handles the price change: <price-editor xmlns:xsql=”urn:oracle-xsql” connection=”momnpup”> <update> <xsql:dml commit=”yes” product_id=”0” bind-params=”new_price product_id”> UPDATE product SET price=? WHERE id=? </xsql:dml> </update> <xsql:dml>COMMIT</xsql:dml> <xsql:include-xsql href=”edit-prod-details.xsql”/> </price-editor> Now you have all of your XSQL pages created. You can test them using URLs to make sure that you are getting the results you want back. In the next section, the stylesheets are created to transform the raw data into something useful for your users. Writing the Stylesheets Earlier in this chapter, you developed the mock Web site. In the previous section, you got the XSQL setup to pull the data from the database. Now you pull the two together using XSLT stylesheets. The elements you’ll use were all covered earlier in this chapter. What you’ll see here is how to fit the pieces together in a real application. As with the preceding XSQL pages, you’ll see how to reuse and nest stylesheets. You’ll also see techniques that are specific to XSQL. You’ll start at the top of the site and develop the home page. Then you’ll handle the two product listing pages—the search results page and the product-by-category page. This section also includes the development of the product category navigational menu. The last page of the public interface is the product details page, and then the two Building XSQL Web Applications 401 stylesheets for the price editor will be developed. Two points of functionality are cov- ered in later sections of this chapter: (1) the stateless paging of product result sets and (2) parameter passing. In reality, you’ll probably want to solve those problems at the same time as the stylesheet problems that you’ll be solving here. However, from a dis- cussion standpoint, it is far easier to cover those topics in their own sections. NOTE Before going any further, there is one fact of XSQL of which you should be aware. Regardless of how you set the rowset and row element names in your XSQL, they will be uppercase in your output. In the preceding examples they were always set uppercase, so you won’t notice the difference. Because XML is case sensitive, though, it’s important to be aware of this before you start writing stylesheet code. If you specify lowercase rowset and row element names in your XSQL and then write your stylesheets expecting those, your stylesheets won’t work. The solution is simple—just uppercase the element names in your stylesheet expressions. First on the hit list is the home page. As with all of the XSQL pages, your first step is to link to the stylesheet in your XSQL. For home.xsql, you should add the following as the second line: <?xml-stylesheet type=”text/xsl” href=”home2.xsl”?> Now it’s time to create the stylesheet itself. The following code is the top of the doc- ument and the main template that is invoked for the top-level element, “home”. There are other templates to add, so you don’t have a closing stylesheet tag yet. <?xml version = ‘1.0’?> <xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0”> <xsl:include href=”banner.xsl”/> <xsl:template match=”/home”> <html> <head> <link rel=”stylesheet” type=”text/css” name=”catalogue” href=”catalogue.css”> </link> </head> <body> <table width=”800” border=”0”> <tr><td colspan=”2” height=”100”> <! banner table > <xsl:call-template name=”banner”/> </td></tr> <tr> <td width=”600”> <! product category table > <xsl:apply-templates select=”PRODUCT_CATEGORIES”/> </td> <td valign=”top” width=”200”> 402 Chapter 14 <! promotion table > <xsl:apply-templates select=”PROMOS”/> </td> </tr> </table> </body> </html> </xsl:template> As promised, there are no problems integrating CSS with XSLT. We’ll use references to CSS styles throughout the code examples. Working down through the example, the next thing to notice is the xsl:include of banner.xsl. The banner.xsl stylesheet contains a single template-named banner. It is called with an xsl:call-template element. Notice that no parameters are passed to it. Here we are using XSLT for a sim- ple purpose—HTML reuse. By separating the banner into its own file, it can be called from all of our files. If we want to change it, we can change it once, and it will be changed throughout the site. The fact that it doesn’t actually interpolate any of the inputted XML data doesn’t actually matter. Here is the banner.xsl stylesheet: <?xml version = ‘1.0’?> <xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0”> <xsl:template name=”banner”> <table width=”100%” height=”100” class=”banner-style” border=”0”> <tr> <td colspan=”2”> <span class=”banner-title”> Mom N’ Pup </span> </td> </tr> <tr> <td align=”left” valign=”top”> <i> <span class=”banner-subtitle”> Catalogue </span> </i> </td> <td align=”right” valign=”top”> <form action=”prod-search.xsql” method=”post”> <span class=”banner-subtitle”> Search: <input name=”search_terms” size=”30”></input> <input type=”submit” value=”go!”></input> </span> </form> </td> </tr> </table> </xsl:template> </xsl:stylesheet> Building XSQL Web Applications 403 The banner code itself isn’t particularly interesting. There aren’t even any XSLT elements besides xsl:stylesheet and xsl:template. It could, of course, contain any XSLT elements. However, because xsl:call-template is used to invoke the template, you don’t know what the context node will be, and thus your XPath expres- sions should be absolute. As discussed in Chapter 13, you can pass parameters to a template that is invoked with xsl:call-template and have functionality similar to a subroutine. The one thing to note in the banner.xsl is the search field. It links to the prod -search.xsql page using a post query. You’ll develop that stylesheet in another cou- ple of pages. For now, it’s time to round out the home.xsl stylesheet that we started earlier. Looking at the top-level template for home.xsql, you can see that two other templates are invoked with apply-templates. These templates in turn invoke their own templates. Let’s start with the “PROMOS” template and its associated template: <xsl:template match=”PROMOS”> <table border=”0”> <xsl:apply-templates select=”PROMO”/> </table> </xsl:template> <xsl:template match=”PROMO”> <tr> <td width=”200” height=”100”> <a> <xsl:attribute name=”href”>prod-details.xsql?product_id=<xsl:value- of select=”PRODUCT_ID”/></xsl:attribute> <img width=”200” height=”100”> <xsl:attribute name=”src”> <xsl:value-of select=”URL”/> </xsl:attribute> </img> </a> </td> </tr> </xsl:template> Looking back at promo.xsql, you’ll see that it pulls two pieces of data on the promo: (1) the product ID and (2) the URL for the promo image. The image is assumed to be 200 x 100. A link is set around the image so that when you click on the image you are taken to the product details page. This template has the first of many uses of the xsl:attribute element to set the value of an HTML attribute. You can’t use an XSLT element inside of an XML element, like <a>, so you have to set the attribute separately. You may notice that the xsl: attribute code isn’t nicely tabbed like the rest of the example. This is purposeful; If you put the xsl:value-of element on its own line, then there will be white space inside of your attribute value. You should always keep all of an xsl:attribute element on one line. The “PRODUCT CATEGORIES” template is the most complex in our entire applica- tion. There are several challenges. First, the categories are separated into columns with 404 Chapter 14 the first categories appearing in the left-hand column and the later categories appear- ing in the right-hand column. This is more complex than listing the columns in a left- to-right ordering. To solve this, we have two separate tables nested into a higher-level table consisting of only two cells. The xsl:apply-templates is called first on all categories that are in the first half of the result set, and then a separate xsl:apply -templates is called on all categories in the second half of the result set. If there is an odd number of categories, the right-hand column will have the extra. <xsl:template match=”PRODUCT_CATEGORIES”> <table border=”0”> <tr> <td valign=”top”> <! left hand table > <table valign=”top” width=”300” border=”0”> <xsl:apply-templates select=”CATEGORY[position() <= (last() div 2) ]”/> </table> </td> <td valign=”top”> <! right hand table > <table valign=”top” width=”300” border=”0”> <xsl:apply-templates select=”CATEGORY[position()>(last() div 2) ]”> <xsl:with-param name=”align-val”>right</xsl:with-param> </xsl:apply-templates> </table> </td> </tr> </table> </xsl:template> Notice that a parameter is passed for the right-hand categories. This is because the mockup requires that the text in the left-hand column be left-adjusted, and the text in the right-hand column be right-adjusted. You could develop two templates—one for each column—but most all of the code would be redundant. Instead, you simply pass a parameter and set the “align” attribute based on the parameter. Because the default value of the parameter is “left”, it isn’t necessary to pass a parameter for the preceding left-hand apply-templates. Here is the “CATEGORY” template that is invoked. <xsl:template match=”CATEGORY”> <xsl:param name=”align-val”>left</xsl:param> <tr> <td> <xsl:attribute name=”align”><xsl:value-of select=”$align- val”/></xsl:attribute> <span class=”category”> <a> <xsl:attribute name=”href”>prod-cat.xsql?category_id=<xsl:value- of select=”ID”/></xsl:attribute> <! product name > Building XSQL Web Applications 405 <b><xsl:value-of select=”NAME”/>. </b> <! product description > <xsl:value-of select=”DESCRIPTION”/>. </a> <i><xsl:apply-templates select=”PRODUCTS”/></i> <a> <xsl:attribute name=”href”>prod-cat.xsql?category_id=<xsl:value-of select=”ID”/></xsl:attribute> . . . </a> </span> </td> </tr> </xsl:template> For this template you pull the text values for the name and description elements for the category and link them to the product category page. You also have to list the first products in the category. The template for this follows. It solves two problems. First, only the first three elements are pulled while the rest are ignored. Second, commas are only inserted between elements 1 and 2 and elements 2 and 3. This is a common prob- lem in XSLT and is easily solved with an xsl:if element along with the position and last functions. The individual product names are linked to the product pages. <xsl:template match=”PRODUCTS”> <xsl:for-each select=”PRODUCTS_ROW[position() <= 3]”> <a> <xsl:attribute name=”href”>prod-details.xsql?product_id=<xsl:value-of select=”./ID”/></xsl:attribute> <xsl:value-of select=”./NAME”/> <xsl:if test=”position() < last()”>, </xsl:if> </a> </xsl:for-each> </xsl:template> </xsl:stylesheet> The last tag is the close of our stylesheet for the home.xsql. You’ll now have a home page that looks like Figure 14.1 that appeared earlier in this chapter, but now all of the data is database driven. What’s really neat is that all of the links and search func- tionality work. You still get back the ugly XML, but you are getting back actual data from the database. Now, it’s time to make the rest of the application pretty. The search results page and the product category page present essentially the same set of challenges. We might as well start with the product category page. On the left of the page is the category directory. As with the banner template, the template for the category directory will be separated into its own file. The main stylesheet along with the stylesheet header is as follows: 406 Chapter 14 <?xml version = ‘1.0’?> <xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0”> <xsl:include href=”banner.xsl”/> <xsl:include href=”cat-nav.xsl”/> <xsl:template match=”/prod-cat”> <html> <head> <link rel=”stylesheet” type=”text/css” name=”catalogue” href=”catalogue.css”> </link> </head> <body> <table width=”800” border=”0”> <tr><td colspan=”2” height=”100”> <! banner table > <xsl:call-template name=”banner”/> </td></tr> <tr> <td width=”200”> <! product category list > <xsl:apply-templates select=”product_categories”/> </td> <td valign=”top” width=”600”> <table> <tr><td> <a href=”home.xsql”>Home</a>: <xsl:value-of select=”//CATEGORY_NAME”/> </td></tr> <tr><td> <! search results > <xsl:apply-templates select=”PRODUCTS”/> </td></tr> </table> </td> </tr> </table> </body> </html> </xsl:template> First, notice that the top-level template references a different element than home.xsl. The top-level home.xsql page outputs “home” as the top-level element, whereas the top-level element here is “prod-cat”. By having a different root element for each XSQL page, you are able to build distinct templates for the different types of data. If you ever need to intermingle the templates, it will be easier to do so. Building XSQL Web Applications 407 As with the home page, the banner template is invoked to create the banner at the top of the page. The product-categories template is in the cat-nav.xsl stylesheet covered later. It handles the directory listing on the left-hand side of the page. From there, the template precedes simply. The category name is pulled from the XML, and then the template for the set of products is invoked. For the category name we use the // to mean “child-or-descendant”. Because this axis appears at the begin- ning of the expression, it means child or descendent of root. This syntax is a little dan- gerous because it assumes that there is only one element of that name in the entire XML document. In our case we know for certain that there is only one CATEGORY_NAME, so it’s okay. The alternative would be to spell out multiple layers in order to access this one data point. XSQL always expects there to be more than one row, so the XML is always structured that way. However, if there really is only one row, it’s just another layer of elements that needs to be navigated. Used with caution, the child-or-descendant axis can make your code a little more readable when you are only pulling one row of data. The products template and its child template, called”PRODUCT”, follow. These are fairly straightforward. For each product in the result set, the product name and sum- mary are listed. The product names are linked to the respective product details pages. As this is the end of the stylesheet, the end tag is also included. <xsl:template match=”PRODUCTS”> <table class=”search-results” width=”100%”> <th><span class=”search-results”>Product</span></th><th>Summary</th> <xsl:apply-templates select=”PRODUCT”/> </table> </xsl:template> <xsl:template match=”PRODUCT”> <tr> <td> <a> <xsl:attribute name=”href”>prod-details.xsql?product_id=<xsl:value- of select=”PRODUCT_ID”/></xsl:attribute> <xsl:value-of select=”PRODUCT_NAME”/> </a> </td> <td><xsl:value-of select=”SUMMARY”/></td> </tr> </xsl:template> </xsl:stylesheet> Before moving onto the product search page, we need to back up and do the cat- egory navigation page. It is a straightforward stylesheet that matches up with the cat-nav.xsql page. The cat-nav.xsql page furnishes the XML as a top-level element, and the cat-nav.xsl page takes that XML and formats into a list of linked category names. <?xml version = ‘1.0’?> <xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0”> <xsl:template match=”product_categories”> 408 Chapter 14 <table valign=”top” width=”100%” height=”100%” class=”cat-directory” border=”0”> <tr><td><b>Categories</b></td></tr> <xsl:apply-templates select=”category”/> </table> </xsl:template> <xsl:template match=”category”> <tr> <td> <a> <xsl:attribute name=”href”>prod-cat.xsql?category_id=<xsl:value-of select=”ID”/></xsl:attribute> <xsl:value-of select=”NAME”/> </a> </td> </tr> <tr> <td height=”10%”> </td> </tr> </xsl:template> </xsl:stylesheet> On to the search results page! The search results page is very similar to the product category page and its full display follows. The one difference is that the linked category name for a product is included in the results. The primary category for the product is used. <?xml version = ‘1.0’?> <xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0”> <xsl:include href=”banner.xsl”/> <xsl:include href=”cat-nav.xsl”/> <xsl:template match=”/prod-search”> <html> <head> <link rel=”stylesheet” type=”text/css” name=”catalogue” href=”catalogue.css”> </link> </head> <body> <table width=”800” border=”0”> <tr><td colspan=”2” height=”100”> <! banner table > <xsl:call-template name=”banner”/> </td></tr> <tr> <td width=”200”> <! product category list > <xsl:apply-templates select=”product_categories”/> </td> <td valign=”top” width=”600”> Building XSQL Web Applications 409 [...]... this, you first need an XSQL page that sets some parameters, though it doesn’t matter what their names are: select deptno from emp where ename=’{@ename}’ . used earlier. <?xml version=”1.0”?> <prod-details connection=”momnpup” xmlns:xsql=”urn :oracle- xsql”> <xsql:include-xsql href=”cat-nav.xsql”/> <xsql:query rowset-element=”PRODUCT-SET” row-element=”DETAILS” product_id=”0” bind-params=”product_id”> SELECT. on the left. <?xml version=”1.0”?> <prod-search connection=”momnpup” xmlns:xsql=”urn :oracle- xsql”> <xsql:include-xsql href=”cat-nav.xsql”/> <xsql:query rowset-element=”PRODUCT_SEARCH” row-element=”PRODUCT”>. to a lookup: <?xml version=”1.0”?> <prod-search connection=”momnpup” xmlns:xsql=”urn :oracle- xsql”> <xsql:query rowset-element=”PRICE_EDITOR_SEARCH” row-element=”PRICE_EDITOR_PRODUCT”>