Building Oracle XML Applications phần 10 ppt

82 254 0
Building Oracle XML Applications phần 10 ppt

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

top of the stylesheet before any other XSLT actions, we've changed UtilData.xsl to be imported instead of included and we've moved both of the <xsl:import> statements to the top of the list, in the appropriate order: <! ForumPageStructure.xsl: Transform the Abstract Structure of a <page> > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:import href="UtilPaging.xsl"/> <xsl:import href="ColumnOverrides.xsl"/> <xsl:include href="UtilBreadcrumbs.xsl"/> <xsl:include href="UtilActions.xsl"/> <xsl:include href="UtilData.xsl"/> Refreshing our Forums.xsql page in the browser, we see what's shown in Figure 17.32 . The forums are now hyperlinks to the drill-down page we'll create next. Figure 17.32. Forum titles show as hyperlinks, paging control is centered We've now basically done all the hard work to set up the abstract page structure and get an example page styled according to our web designer's specifications. Creating additional pages simply involves coming up with the XSQL page to represent the structure and data for new pages, and possibly introducing additional column-level overrides if we have to do one-off processing. Figure 17.33 illustrates all the pages we will build. One down, seven to go. Figure 17.33. Map of XSQL pages to implement discussion forum To create the drill-down ForumTopics.xsql page, we throw together the XSQL page describing its breadcrumbs, actions, data, and paging, and we're done. Example 17.31 shows these four structural parts in a single XSQL data page template. Example 17.31. XSQL Page to Display List of Topics for a Forum <?xml version="1.0"?> <! ForumTopics.xsql: Show list of topics for a forum > <?xml-stylesheet type="text/xsl" href="ForumStyle.xsl"?> <page connection="xmlbook" xmlns:xsql="urn:oracle-xsql"> <! Include request params so Actions can check for forumuser cookie > <xsql:include-request-params/> <xsql:action handler="Paging" rows-per-page="5" url-params="id"> SELECT COUNT(t.id) AS "total" FROM forum_topic t WHERE forumid = {@id} </xsql:action> <breadcrumbs> <xsql:query> SELECT name AS "forumname", id AS "forumid" FROM forum WHERE id = {@id} </xsql:query> </breadcrumbs> <actions> <link page="EnterForumTopic.xsql" label="Enter a New Topic" login="yes"> <xsql:include-param name="id"/> </link> <link page="Search.xsql" label="Search"> <xsql:include-param name="id"/> </link> </actions> <data> <xsql:query max-rows="{@paging-max}" skip-rows="{@paging-skip}"> SELECT t.id AS h_id, t.title AS "Topic", t.userid AS "Started_By", postings-1 AS "Replies", to_char(lastpost,'dd Mon YYYY, hh24:mi') as "Last_Post" FROM forum_topic t WHERE forumid = {@id} ORDER BY 5 desc </xsql:query> </data> </page> Note a few interesting things about this page: • It uses <xsql:include-request-params> because one of its actions requires a login. Recall that the actions template needs to check for the presence of a cookie in the request to detect if the user is logged in. • The count query inside the <xsql:action> handler that creates the paging section uses the {@id} to count just the topics in the current forum whose id is passed in the URL. • The forumname and forumid for the breadcrumbs are queried from the database since only the forumid is passed into the page. • Like every page on our site, it refers to the standard ForumStyle.xsl stylesheet. Now if we click on the "XML" forum name from the Forums.xsql page to drill-down to a list of its topics, we see our new ForumTopics.xsql page in action as shown in Figure 17.34 . Figure 17.34. Drill-down display of topics for a selected forum As expected, the breadcrumbs properly reflect where we are in the site; the action bar indicates the actions we can perform; the data is formatted in a consistent tabular format; and the paging display is functional. The column override template for ROW/Topic that we created earlier is already doing its job of formatting the Topic as a hyperlink to the next-level drill-down page: TopicPostings.xsql. Note that since we haven't set our forumuser cookie yet, the action bar displays the "Enter a New Topic" link as "Login to Enter a New Topic" with a hyperlink to the Login.xsql page as expected. The TopicPostings.xsql page appears in Example 17.32 . Example 17.32. XSQL Page to Display List of Postings for a Topic <?xml version="1.0"?> <! TopicPostings.xsql: Show list of postings for a given topic > <?xml-stylesheet type="text/xsl" href="ForumStyle.xsl"?> <page connection="xmlbook" xmlns:xsql="urn:oracle-xsql"> <! Include request params so Actions can check for forumuser cookie > <xsql:include-request-params/> <breadcrumbs> <xsql:query> SELECT t.forumid as "forumid", f.name AS "forumname", t.id as "topicid", t.title AS "topicname" FROM forum_topic t, forum f WHERE t.id = {@id} AND f.id = t.forumid </xsql:query> </breadcrumbs> <actions> <link page="EnterForumTopicReply.xsql" label="Post a New Reply" login="yes"> <xsql:include-param name="id"/> </link> </actions> <data> <xsql:query> SELECT id as h_id, userid AS "Posted_By", posting AS "Posting", TO_CHAR(posted,'dd Mon yyyy, hh24:mi') AS "H_Posted_On" FROM forum_topic_posting WHERE topicid = {@id} ORDER BY posted </xsql:query> </data> </page> This page does not need a paging section since we want the user to be able to read all the sequential postings in a single page. Again, the breadcrumbs are selected from the database, but this time we're getting information on both the forumname and the topicname, based on the topicid passed into the page. 17.3.5 Using Recursive Named Templates Clicking from the ForumTopics.xsql page on a particular topic name's hyperlink now brings us to a list of all the postings for that topic as illustrated in Figure 17.35 . Figure 17.35. Display of all postings for a particular topic This looks exactly like what we want; however, the text of the posting is a little jumbled for the Java code example I posted. It would be nice to format the text in a monospaced font and preserve the spacing and carriage returns so that a posted code example could be understood by others reading the postings. It's not as easy as simply formatting the text as an HTML <pre> tag, since preformatted text and table cells don't get along so nicely in HTML. The solution involves replacing carriage returns in the text of the posting with an HTML <br> tag so that a line break is reflected without using the <pre> mode. Preserving indentation is a little tricky too since, in general, whitespace in HTML is generally not treated as relevant, except in the <pre> sections that we cannot use here. So, we create the following named template subroutines: br-replace Replaces carriage return with <br> sp-replace Replaces consecutive spaces with non-breaking spaces The br-replace and sp-replace named templates in Example 17.33 illustrate a general technique that will likely come in handy for future applications: recursive named templates. We need to use this more elaborate technique for generalized text substitution since the XPath translate( ) function we saw in UtilData.xsl only allows one character x to be substituted by another character y. If we study the br-replace template, we see that it accepts a parameter named text. This will contain the text passed in by the invoking template for which carriage returns need to be substituted by <br> tags. Example 17.33. Library Stylesheet of Text-Formatting Routines <! UtilTest.xsl: Common text formatting routines > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <! Replace new lines with html <br> tags > <xsl:template name="br-replace"> <xsl:param name="text"/> <xsl:variable name="cr" select="'&#xa;'"/> <xsl:choose> <! If the value of the $text parameter contains a carriage return > <xsl:when test="contains($text,$cr)"> <! Return the substring of $text before the carriage return > <xsl:value-of select="substring-before($text,$cr)"/> <! And construct a <br/> element > <br/> <! | Then invoke this same br-replace template again, passing the | substring *after* the carriage return as the new "$text" to | consider for replacement + > <xsl:call-template name="br-replace"> <xsl:with-param name="text" select="substring-after($text,$cr)"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template> <! Replace two consecutive spaces w/ 2 non-breaking spaces > <xsl:template name="sp-replace"> <xsl:param name="text"/> <xsl:variable name="sp"><xsl:text> </xsl:text></xsl:variable> <xsl:choose> <xsl:when test="contains($text,$sp)"> <xsl:value-of select="substring-before($text,$sp)"/> <xsl:text>&#160;&#160;</xsl:text> <xsl:call-template name="sp-replace"> <xsl:with-param name="text" select="substring-after($text,$sp)"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> For convenience, the template selects a literal carriage return character represented by the numerical character entity &#xa; into a cr variable. This variable is used in the <xsl:choose> element's clause: <xsl:when test="contains($text,$cr)"> which uses the XPath contains( ) function to see if the value of the $text parameter contains the value of the $cr parameter, that is, if $text contains a carriage return. If it contains a carriage return, we select the value of the substring of $text located before the carriage return using substring-before($text,$cr). We then create a literal <br/> element, followed by a recursive invocation of the br-replace template, passing substring-after($text,$cr) to see if the remainder of the string has any further carriage returns. In the template's <xsl:otherwise> clause, which will be executed when $text contains no carriage returns, we simply return the value of $text. If br-replace has been called recursively, this ends the recursion. The sp-replace template is identical to br-replace except that it replaces the occurrence of two consecutive space characters with two consecutive non-breaking space characters represented by &nbsp;&nbsp;. We apply these by adding a third column override template now for the ROW/Posting pattern in our ColumnOverrides.xsl stylesheet, like this: <! Anywhere a Posting appears in a <ROW>, Format it as Code > <xsl:template match="ROW/Posting"> <td> <span class="date"> <xsl:text>Posted </xsl:text> <xsl:value-of select=" /H_Posted_On"/> </span> <hr/> <span class="code"> <xsl:call-template name="br-replace"> <xsl:with-param name="text"> <xsl:call-template name="sp-replace"> <xsl:with-param name="text" select="."/> </xsl:call-template> </xsl:with-param> </xsl:call-template> </span> </td> </xsl:template> posting will now show up with its carriage returns and spaces replaced by HTML-savvy equivalents, allowing our posting to be displayed in a monospaced font without having to use a <pre> element. Now we touch the timestamp on our main ForumStyle.xsl stylesheet to cause the XSQL page processor to reload it along with all the stylesheets it includes or imports. We'll immediately see the difference in the display of our posting when refreshing the TopicPosting.xsql page as shown in Figure 17.36 . Figure 17.36. User text in postings with nicely wrapped, monospaced font That looks a lot better! Next, we can knock off the TodaysActiveTopics.xsql page by coming up with the right couple of queries in the underlying XSQL page. The page for TodaysActiveTopics.xsql is shown in Example 17.34 . Example 17.34. XSQL Page to Display Discussion Topics Active Today <?xml version="1.0"?> <! TodaysActiveTopics.xsql: Listing of topics active today > <?xml-stylesheet type="text/xsl" href="ForumStyle.xsl"?> <page connection="xmlbook" xmlns:xsql="urn:oracle-xsql"> <xsql:action handler="Paging" rows-per-page="5"> SELECT count(t.id) AS "total" FROM forum_topic t, forum f WHERE t.forumid = f.id AND t.lastpost BETWEEN TRUNC(SYSDATE) AND TRUNC(SYSDATE+1) </xsql:action> <breadcrumbs> <forumname>Active Topics Today</forumname> </breadcrumbs> <data> <xsql:query skip-rows="{@paging-skip}" max-rows="{@paging-max}"> SELECT t.id AS h_id, t.title AS "Topic", f.name AS "Forum" FROM forum_topic t, forum f WHERE t.forumid = f.id AND t.lastpost BETWEEN TRUNC(SYSDATE) AND TRUNC(SYSDATE+1) ORDER BY t.lastpost desc </xsql:query> </data> </page> Clicking on the Active Topics Today link from the Forums.xsql home page now shows us the list of all topics across all forums that have been updated today as illustrated in Figure 17.37 . Figure 17.37. List of all active discussion topics across all forums 17.3.6 Reusing Templates to Generate Forms We need to build a few HTML forms based on the tasks for: • Logging into the forum by providing a username • Entering a new topic in a forum • Posting a new reply to an existing forum topic • Searching the forums Since we designed the UtilDataForm.xsl stylesheet earlier in this chapter with templates to format HTML forms based on a structural description, we can reuse it here. The abstract structure of our page can be enhanced to allow an optional <dataform> section. By including the UtilDataForm.xsl stylesheet in our ForumPageStructure.xsl and adding one additional xsl:apply-templates with a select="dataform", like this: [...]... Connect as XMLBOOK using SQL*Plus and run the install_helper_packages.sql script: sqlplus xmlbook/xmlbook @install_helper_packages.sql: A.2 Source Code for the XML Helper Packages The xml, xmldoc, xpath, and xslt packages depend on having the Oracle XML Parser for PL/SQL installed (See Chapter 5 for installation details) In addition, since the Oracle XML Parser for PL/SQL wraps the Oracle XML Parser... '80'); Parse and return an XML document FUNCTION parse (xml VARCHAR2) RETURN xmldom.DOMDocument; FUNCTION parse (xml CLOB) RETURN xmldom.DOMDocument; FUNCTION parse (xml BFILE) RETURN xmldom.DOMDocument; Parse and return an XML Document by URL FUNCTION parseURL(url VARCHAR2) RETURN xmldom.DOMDocument; Free the memory used by an XML document PROCEDURE freeDocument(doc xmldom.DOMDocument); END; CREATE... parser := xmlparser.newParser; xmlparser.parseBuffer(parser ,xml) ; retDoc := xmlparser.getDocument(parser); xmlparser.freeParser(parser); RETURN retDoc; EXCEPTION WHEN parse_error THEN xmlparser.freeParser(parser); RETURN retdoc; END; FUNCTION parse (xml BFILE) RETURN xmldom.DOMDocument IS retDoc xmldom.DOMDocument; parser xmlparser.Parser; b BFILE := xml; c CLOB; BEGIN IF xml IS NULL THEN RETURN NULL;... RETURN retdoc; END; FUNCTION parse (xml CLOB) RETURN xmldom.DOMDocument IS retDoc xmldom.DOMDocument; parser xmlparser.Parser; BEGIN IF xml IS NULL THEN RETURN NULL; END IF; setProxy; parser := xmlparser.newParser; xmlparser.parseCLOB(parser ,xml) ; retDoc := xmlparser.getDocument(parser); xmlparser.freeParser(parser); RETURN retDoc; EXCEPTION WHEN parse_error THEN xmlparser.freeParser(parser); RETURN... functionality for parsing XML documents from VARCHAR2, CLOB, BFILE, and URL sources It uses the Oracle XML Parser for PL/SQL's xmlparser package To use these routines, perform these steps: 1 Call one of the xml. parse functions to parse your XML document 2 Work with the returned xmldom.DOMDocument 3 Call xml. freeDocument(yourDoc) to free the memory used by the parsed representation of your XML document It is... already: o Installed the Oracle XML Parser for Java in your schema o Installed the Oracle XML Parser for PL/SQL packages in your schema, and o Been granted the JAVAUSERPRIV privilege to execute Java code inside Oracle8 i • Alternatively, you must have been granted EXECUTE permission on the Oracle XML Parser for PL/SQL packages installed in another schema A.2.1 The xml Package The xml package provides key... RETURN xmldom.DOMDocument IS xmldoc xmldom.DOMDocument; BEGIN IF url IS NULL THEN RETURN NULL; END IF; setProxy; RETURN xmlparser.parse(url); END; Free the Java objects associated with an in-memory DOM tree PROCEDURE freeDocument(doc xmldom.DOMDocument) IS BEGIN xmldom.freeDocument(doc); END; END; A.2.2 The xmldoc Package The xmldoc package provides three key functions for saving well-formed XML documents... xmldoc VARCHAR2, VARCHAR2, docommit BOOLEAN := TRUE); PROCEDURE save(name xmldoc VARCHAR2, CLOB, docommit BOOLEAN := TRUE); PROCEDURE save(name xmldoc VARCHAR2, BFILE, docommit BOOLEAN := TRUE); PROCEDURE save(name VARCHAR2, xmldoc xmldom.DOMDocument, docommit BOOLEAN:=TRUE); Get an XML document by name from the xml_ documents table FUNCTION get(name VARCHAR2) RETURN xmldom.DOMDocument; Get an XML. .. FUNCTION get(name VARCHAR2) RETURN xmldom.DOMDocument IS BEGIN RETURN xml. parse(getAsCLOB(name)); END; PROCEDURE save(name VARCHAR2,xmldoc VARCHAR2,docommit BOOLEAN:=TRUE) IS c CLOB := get(name, createNew=>TRUE); doc xmldom.DOMDocument; BEGIN doc := xml. parse(xmldoc); xmldom.writeToClob(doc,c); xml. freeDocument(doc); IF docommit THEN commit; END IF; EXCEPTION WHEN OTHERS THEN xml. freeDocument(doc); RAISE;... VARCHAR2,xmldoc CLOB,docommit BOOLEAN:=TRUE) IS c CLOB := get(name, createNew=>TRUE); doc xmldom.DOMDocument; BEGIN doc := xml. parse(xmldoc); xmldom.writeToClob(doc,c); xml. freeDocument(doc); IF docommit THEN commit; END IF; EXCEPTION WHEN OTHERS THEN xml. freeDocument(doc); RAISE; END; PROCEDURE save(name VARCHAR2,xmldoc BFILE,docommit BOOLEAN:=TRUE) IS c CLOB := get(name, createNew=>TRUE); doc xmldom.DOMDocument; . looks like this: < ?xml version="1.0"?> < ?xml- stylesheet type="text/xsl" href="ForumStyle.xsl"?> <page xmlns:xsql="urn :oracle- xsql">. type="text/xsl" href="ForumStyle.xsl"?> <page connection="xmlbook" xmlns:xsql="urn :oracle- xsql"> <! Include request params so Actions can check for. type="text/xsl" href="ForumStyle.xsl"?> <page connection="xmlbook" xmlns:xsql="urn :oracle- xsql"> <xsql:action handler="Paging" rows-per-page="5">

Ngày đăng: 08/08/2014, 18:21

Tài liệu cùng người dùng

Tài liệu liên quan