1. Trang chủ
  2. » Công Nghệ Thông Tin

Building Oracle XML Applications phần 10 ppt

82 255 0

Đ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

Thông tin cơ bản

Tiêu đề Building Oracle XML Applications phần 10 ppt
Trường học University of Information Technology and Communication
Chuyên ngành Database Applications
Thể loại lecture notes
Thành phố Hanoi
Định dạng
Số trang 82
Dung lượng 0,95 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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, a

Trang 1

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"/>

Figure 17.33 illustrates all the pages we will build One down, seven to go

Trang 2

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"

Trang 3

<xsql:query max-rows="{@paging-max}" skip-rows="{@paging-skip}">

SELECT t.id AS h_id,

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

Trang 4

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>

Trang 5

<link page="EnterForumTopicReply.xsql" label="Post a New Reply" login="yes"> <xsql:include-param name="id"/>

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,

Trang 6

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 >

| Then invoke this same br-replace template again, passing the

| substring *after* the carriage return as the new "$text" to

| consider for replacement

+ >

Trang 7

<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;

Trang 8

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 >

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

Trang 9

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:query skip-rows="{@paging-skip}" max-rows="{@paging-max}">

SELECT t.id AS h_id,

Trang 10

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:

Trang 11

<! 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="UtilData.xsl"/>

all of the HTML forms will be rendered automatically across the whole site

The Login.xsql form requires a very simple form structure, so its XSQL page looks like this:

<dataform target="Forums.xsql" submit="Login">

<item type="text" name="userid" label="Your Email"/>

</dataform>

</page>

With this in place, clicking on a link in the action bar like "Login to Enter a New Topic" brings us

to a login page like the one shown in Figure 17.38

Trang 12

Figure 17.38 Simple login form

Notice that the target attribute indicates that the HTML form submission will be handled by our

home page, Forums.xsql We need to add one additional XSQL action element to the top of the Forums.xsql page to receive the userid parameter and set the forumuser cookie with its value:

<! Added to the top of the Forums.xsql page to set forumuser cookie >

<xsql:set-cookie name="forumuser" value="{@userid}"

ignore-empty-value="yes" only-if-unset="yes"/>

Now submitting the login page will set the cookie and show the user the list of discussion forums again At that point they will now see action links like "Enter a New Topic" and "Post a New Reply" instead of the links asking them to log in

Example 17.35 shows the EnterForumTopic.xsql page to create the form used for entering a new

topic in a forum

Example 17.35 XSQL Page to Enter a New Topic in a Forum

<?xml version="1.0"?>

<! EnterForumTopic.xsql: Form to enter a new topic in a forum >

<?xml-stylesheet type="text/xsl" href="ForumStyle.xsl"?>

<page connection="xmlbook" xmlns:xsql="urn:oracle-xsql">

<breadcrumbs>

<xsql:query>

SELECT name as "forumname", id AS "forumid",

'Enter a New Topic' AS "topicname"

FROM forum

WHERE id = {@id}

</xsql:query>

</breadcrumbs>

<dataform target="ForumTopics.xsql" submit="Create Your New Topic">

<item type="hidden" name="id">

<xsql:include-param name="id"/>

</item>

<item type="text" name="userid" label="Your Email">

Trang 13

<xsql:include-param name="forumuser"/>

</item>

<item type="text" name="title" size="60" label="Topic Subject"/>

<item type="textarea" name="posting" size="60" label="Your Message"/>

</dataform>

</page>

This defines a dataform with a hidden item, a text item, and a textarea We indicate that the

HTML form should be posted to the ForumTopics.xsql page, and add the following extra XSQL action element to the top of ForumTopics.xsql to handle the posted HTML form and insert it into

the forum_new_topic view

<! Added to the top of the ForumTopics.xsql page to handle new posted topic >

<xsql:insert-request table="forum_new_topic" transform="InsertPostedTopic.xsl"/>

When users are just browsing the ForumTopics.xsql page, this action element is a no-op

We need an insert transformation to transform the XML document representing the posted HTML form into the appropriate ROWSET structure for the forum_new_topic table We can generate a

skeleton for this automatically by again using our GenerateInsertTransform.xsql page with the

<FORUMID>, <TITLE>, <USERID>, and <POSTING> elements, as shown in Example 17.36

Example 17.36 Insert Transform for the forum_new_topic Table

<! Created by GenerateInsertTransform.xsl >

<! InsertPostedTopic.xsl: Insert transform for forum_new_topic table >

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <! Transform /request/parameters into ROWSET for forum_new_topic >

Trang 14

Now we can click on "Enter a New Topic" and we'll see our EnterForumTopic.xsql HTML form

appear It appears in Figure 17.39

Figure 17.39 Form to enter a new discussion topic

The current userid from the forumuser cookie was selected in the XSQL data page as the content

of the dataform/item element for "Your Email," so this value defaults automatically Submitting the form now inserts the new posting and shows it at the top of the list of postings for the forum The database trigger we created on the forum_new_topic view silently does its job of inserting a row into the forum_topic table and a row into the forum_topic_posting table The database trigger on forum_topic_posting automatically adjusts the number of postings and the lastpost

date for the forum

The form to enter a reply to a posting should display a form, as well as the history of current replies on the topic so the user formulating a reply can consult the trail of previous users' thoughts If we include both a <dataform> section and a <data> section in the XSQL page for

Trang 15

EnterForumTopicReply.xsql, our overarching ForumPageStructure.xsl stylesheet with its pagetemplate will cause all the ingredients to fall perfectly into place The EnterForumTopicReply.xsql

page appears in Example 17.37

Example 17.37 XSQL Page to Post a Reply to a Forum Topic

<?xml version="1.0"?>

<! EnterForumTopicReply.xsql: Form to post a reply on a topic >

<?xml-stylesheet type="text/xsl" href="ForumStyle.xsl"?>

<page connection="xmlbook" xmlns:xsql="urn:oracle-xsql">

<breadcrumbs>

<xsql:include-xsql href="ForumTopicLookup.xsql"/>

</breadcrumbs>

<dataform target="TopicPostings.xsql" submit="Post Your Reply">

<item type="hidden" name="id">

We need to make changes to TopicPostings.xsql similar to what we did for the previous example

to handle the posted HTML form and insert it into the forum_topic_posting table So we add an

<xsql:insert-request> to the top of TopicPostings.xsql:

<! Added to the top of the TopicPostings.xsql page

to handle new posted topic >

<xsql:insert-request table="forum_topic_posting"

transform="InsertPostedReply.xsl"/>

Again employing our handy utility to create the skeleton insert transformation for the

forum_topic_posting table, we execute the command:

xsql GenerateInsertTransform.xsql InsertPostedReply.xsl table=forum_topic_posting

and edit the skeleton stylesheet to produce the InsertPostedReply.xsl transformation in Example 17.38

Trang 16

Example 17.38 Insert Transform for the forum_topic_posting Table

<! Created by GenerateInsertTransform.xsl >

<! InsertPostedReply.xsl: Insert transform for forum_topic_posting table >

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <! Transform /request/parameters into ROWSET for forum_topic_posting > <xsl:template match="/">

Note that since our table's BEFORE INSERT trigger will automatically assign the ID and POSTED

columns, we can comment them out of the insert transformation template or remove these sections completely

We're ready now to try replying to a posting Clicking on the "Post a New Reply" link from the

TopicPostings.xsql page, we'll see our new form, as shown in Figure 17.40

Trang 17

Figure 17.40 Form to let user post a reply on a discussion

topic

Notice that our dataform structure from the underlying XSQL page was transformed into the HTML form as desired, and the data section containing the query to produce the list of current postings in date order is formatted by the data template Since the query produces a

ROW/Posting element, the ROW/Posting template we created in our ColumnOverrides.xsl

stylesheet formats the Posting as HTML-friendly code listings, just as it did on the

TopicPostings.xsql page

We're nearly done The last feature to build is sitewide searching

17.3.7 Dynamic Queries Using Ref Cursors

We create a Search.xsql page in Example 17.39 to display the search form It uses several list-style items instead of just text and textarea like the earlier forms

Example 17.39 XSQL Page to Drive the Forum Search Criteria Form

<?xml version="1.0"?>

<! Search.xsql: Forum search criteria form >

<?xml-stylesheet type="text/xsl" href="ForumStyle.xsl"?>

<page connection="xmlbook" xmlns:xsql="urn:oracle-xsql">

<breadcrumbs>

<forumname>Search</forumname>

</breadcrumbs>

Trang 18

<dataform target="ForumSearchResults.xsql" submit="Search">

<xsql:set-page-param name="default" value="{@id}"/>

<item type="text" name="searchFor" size="30" label="Search For"/>

<item type="list" name="searchIn" label="In">

<ROW><VALUE>-7</VALUE><DISPLAY>In Past Week</DISPLAY></ROW>

<ROW><VALUE>-14</VALUE><DISPLAY>In Past Two Weeks</DISPLAY></ROW>

<ROW><VALUE>-21</VALUE><DISPLAY>In Past Three Weeks</DISPLAY></ROW>

as a parameter since new forums might be added at any time In case no item ID is passed into

the Search.xsql page, the query also includes a UNION ALL with the statement:

SELECT -1, 'All Forums' FROM dual

to include that as a default choice in the list

When clicking the search action from within a forum, the forum ID is passed as a parameter to the

search.xsql page, and the default behavior is to search for text only within the current forum If

Trang 19

the user clicks on "SEARCH from the Forum list," no ID is passed, so the "All Forums" entry we

added becomes the default instead

Our Search.xsql form then will look like Figure 17.41

Figure 17.41 Form allowing user to search the discussion

forum

The Search.xsql page targets the ForumSearchResults.xsql page so that the search form

parameters can be used to query the database and present the search results What query do we

include in the ForumSearchResults.xsql page? The query will need to look different depending on

what combination of search form parameters the user has set As we learned in Chapter 15,

<xsql:ref-cursor-function> handles all the dynamic aspects inside a stored package function that programmatically determines the query statement, executes that dynamic query, and returns a cursor to the XSQL page to render the results as XML

Since we want to be able to page through query results, we need to pass the various parameters that affect the query to the stored package function, and have it return us both the actual rows retrieved by the dynamic query and a count we can use as the count query of our Paging action handler Example 17.40 shows the ForumSearch package that gets the job done

Example 17.40 Package to Handle Dynamic Discussion Forum Site Search

CREATE OR REPLACE PACKAGE ForumSearch IS

TYPE ref_cursor IS REF CURSOR;

FUNCTION Find(forumid NUMBER := -1,

daysAgo NUMBER := 0,

searchIn VARCHAR2 := 'S',

searchFor VARCHAR2 := NULL) RETURN ref_cursor;

FUNCTION Hits(forumid NUMBER := -1,

daysAgo NUMBER := 0,

Trang 20

searchIn VARCHAR2 := 'S',

searchFor VARCHAR2 := NULL) RETURN NUMBER;

END;

CREATE OR REPLACE PACKAGE BODY ForumSearch IS

FUNCTION Query(forumid NUMBER := -1,

daysAgo NUMBER := 0,

searchIn VARCHAR2 := 'S',

searchFor VARCHAR2 := NULL) RETURN VARCHAR2 IS

query VARCHAR2(2000);

noCriteriaSupplied BOOLEAN := LTRIM(RTRIM(searchFor)) IS NULL;

searchEntireMessage BOOLEAN := UPPER(searchIn)='E';

restrictToForum BOOLEAN := forumid > 0;

restrictByDate BOOLEAN := daysAgo < 0;

WHERE t.id = p.topicid

AND t.forumid = f.id';

IF searchEntireMessage THEN

query := query ||' AND ( CONTAINS(p.posting, '''||searchFor||''')>0 '|| ' OR UPPER(t.title) LIKE UPPER(''%'||searchFor||'%''))'; ELSE

query := query || ' AND UPPER(t.title) LIKE UPPER(''%'||searchFor||'%'')'; END IF;

Trang 21

FUNCTION Hits(forumid NUMBER := -1,

The package-private Query( ) function figures out the SQL statement based on all the

parameters passed in Notice that if the user has indicated a search not just in the topic title, but

in the message body as well, the Query( ) function appends a WHERE clause using an interMedia CONTAINS query to do a text search through the postings

The public Find( ) function returns the ref cursor of query results returned by the dynamically determined query, while the public Hits( ) function returns the count of the number of rows retrieved by the dynamically determined query

With all the heavy lifting being done behind the scenes by this database package, the XSQL page

in Example 17.41 looks pretty simple

Trang 22

Example 17.41 XSQL Page to Drive Discussion Forum Search Results

<?xml version="1.0"?>

<! ForumSearchResults.xsql: Paging display of search 'hits' >

<?xml-stylesheet type="text/xsl" href="ForumStyle.xsl"?>

<page connection="xmlbook" xmlns:xsql="urn:oracle-xsql">

<xsql:action handler="Paging" rows-per-page="5"

url-params="forum daysAgo searchIn searchFor">

in which no parameter value is passed in, we're using a combination of adding zero to number arguments and the NVL( ) function for string arguments

We create the functional index to allow us to quickly search the topic headings in a

case-insensitive way:

CREATE INDEX forum_topic_title_idx ON forum_topic(UPPER(title));

and create an interMedia index using the autosectioner we learned about in Chapter 13, to enable searching on text or XML elements that might be contained in the posting document body:

Trang 23

CREATE INDEX forum_topic_posting_idx ON forum_topic_posting(posting)

INDEXTYPE IS ctxsys.contextPARAMETERS ('section group ctxsys.auto_section_group');

With that, we're done We can now click on the Search action link on any page where it appears,

enter search criteria using the Search.xsql form, and then browse the results of the dynamically

determined query in a way that's totally consistent with every other page in the site Figure 17.42

illustrates browsing the search results

Figure 17.42 Browsing results from a cross-forum search

We've come a long way in a short time We've directly experienced several examples now of separating data from presentation and pragmatically implementing it using a combination of Oracle XSQL Pages to handle the assembly of the data page and XSLT stylesheets to handle the modular presentation for anything from one page to an entire web site

17.3.8 Unifying Our News Portal and Discussion Forum

As a final fun project, let's tie together the news portal and the discussion forum we've built with

an XSLT-driven tab-page system Just as we did earlier for the abstract structure of pages, we use

a Site.xsql page, shown in Example 17.42, to reflect the structure of our site:

Example 17.42 XSQL Page to Drive Tab Set

<?xml version="1.0"?>

<! Site.xsql: Provide tabset structure for home page >

<?xml-stylesheet type="text/xsl" href="tab.xsl"?>

<site elt="query" xmlns:xsql="urn:oracle-xsql">

<!

| Pass the values of current "tab" parameter (if passed in explicitly),

| the "lasttab" cookie (if set), and the name of this page to the

Trang 24

| XSLT stylesheet that renders the tab bar

+ >

<xsql:set-stylesheet-param name="thispage" value="site.xsql"/>

<xsql:set-stylesheet-param name="tab" value="{@tab}" ignore-empty-value="yes"/> <xsql:set-stylesheet-param name="lasttab" value="{@lasttab}"

ignore-empty-value="yes"/>

<! Remember the last tab clicked in an HTTP Cookie >

<xsql:set-cookie name="lasttab" value="{@tab}" ignore-empty-value="yes"/> <! This is static XML that provides the tab structure >

<tabs>

<tab id="News" name="News"/>

<tab id="Forums" name="Forums"/>

</tabs>

</site>

We're using some <xsql:set-stylesheet-param> elements to pass a few tab-related

parameters to the Tab.xsl stylesheet in Example 17.43 so the stylesheet can know the currently

selected tab The Site.xsql page also uses <xsql:set-cookie> to keep track of the latest tab

chosen by the user Tab.xsl contains templates to match the site element as well as named

templates that match the selected and unselected tabs Although our site will only have the

"News" and "Forums" tabs above, you can easily add more tabs by changing the structural information in the site/tabs section of your data page

Example 17.43 Stylesheet to Render a Set of HTML Tabs for a Frameset

<xsl:when test="$tab"><xsl:value-of select="$tab"/></xsl:when>

<xsl:when test="$lasttab"><xsl:value-of select="$lasttab"/></xsl:when> <xsl:otherwise>

Trang 25

<a href=" /index.html" target="_parent">

<img src="{$i}banner.gif" width="342" height="69" border="0"/>

<xsl:template match="tab"> <! Match a regular tab >

<td bgcolor="#B6B687" width="1%" align="LEFT" valign="TOP"><img

src="{$i}tab_open.gif" height="21" width="13" border="0" /></td>

<td width="1%" bgcolor="#B6B687">

Trang 26

<a target="contents" href="{@id}.xsql"

<td bgcolor="#B6B687" width="1%" align="RIGHT" valign="TOP">

<img src="{$i}tab_close.gif" height="21" width="10" border="0"/>

<td bgcolor="#336699" width="1%" align="RIGHT" valign="TOP">

<img src="{$i}ctab_close.gif" height="21" width="12" border="0"/>

</td>

</xsl:template>

</xsl:stylesheet>

And finally, a little index.html page ties the tabs frame and defaults the News.xsql page to be the

default content in the main section of the page:

<html>

<head>

<title>XML Book XSQL Sample Site</title>

</head>

<frameset border="no" rows="90,*">

<frame frameborder=no noresize name="tabs" src="site.xsql">

<frame frameborder=no name="contents" src="News.xsql">

</frameset>

</html>

Figure 17.43 illustrates what the user now sees when logged into the site, with the additional tabs

in place The news portal page is the initial tab displayed

Trang 27

Figure 17.43 Final news portal and discussion application

with tabs

Clicking on the Forums tab causes Forums.xsql to be requested in the main content frame,

producing our discussion forum home page on that tab

And with this final touch of grace, our journey is complete

In conclusion, we've demonstrated:

• The speed, functionality, and reliability of the Oracle database

• The power of XML as a universal standard for data exchange

• The flexibility of XSLT to transform data into any format required

These factors give us a real leg up in the race to build the next great web application Throughout

this book, we've learned how the powerful features of XML, XSLT, and Oracle8i—in combination

with Oracle XML technologies like the XML Parser, XSLT processor, XML SQL Utility, and XSQL Pages—allow us to:

• Extract data from a database in XML format

• Search and transform XML data using XSLT and XPath

• Send and receive XML datagrams over the Web

• Store datagrams of any shape and size in the database

• Search efficiently through millions of XML documents

• Assemble XML information and transform it for delivery in any needed format

Now, excited by the opportunities that XML and the Oracle XML technologies enable, all that's left

to do is to "go forth and transform!"

Trang 28

Part IV: Appendixes

This part of the book contains the following reference appendixes:

Appendix A, explains the source code for the PL/SQL helper packages we built in Chapter 3: xml,

xmldoc, xpath, xslt, and http

Appendix B, describes how to install the XSQL Servlet that you can use with any servlet engine (Apache JServ, JRun, etc.)

Appendix C, graphically summarizes the relationships between key XML concepts and the family

of XML-related standards that support them

Appendix D, provides cheat sheets on XML, XSLT, and XPath syntax

Trang 29

Appendix A XML Helper Packages

This appendix includes the PL/SQL package implementations for the XML helper packages we used back in Chapter 5:

A.1 Installing the XML Helper Packages

To install all of the XML helper packages we used in Chapter 5, follow these steps:

1 Change directory to the /examples/appa directory, which contains the files for this

appendix

2 Connect as SYS using SQL*Plus and run the install_sys_helper_packages.sql:

sqlplus sys/change_on_install @install_sys_helper_packages.sql

3 Compile PropertyHelper.java and use loadjava to load it into the database as SYS:

4 javac PropertyHelper.java

loadjava -verbose -resolve -user sys/change_on_install PropertyHelper.class

5 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 for Java, one of the following must be true before you can successfully compile and run these packages:

• You must have 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 Oracle8i

Trang 30

• 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 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 safe to cache the instances of xmldom.DOMDocument in PL/SQL package-level variables for parsed XML documents you need to use over and over during the same database session, but remember that the memory they occupy is not freed until you explicitly call xml.freeDocument Note that if you need to parse an XML document from a URL outside a firewall, or parse any XML document with external references (external entities or DTD, for example) based on URLs outside

a firewall, you must call:

xml.setHttpProxy('proxyServerName');

once in your current database session before using the parse functions The various parsefunctions handle both creating and freeing the xmlparser.parser object used to create the in-memory DOM tree representation of your parsed XML file

Here is the source code for the xml package:

CREATE OR REPLACE PACKAGE xml AS

Set HTTP proxy server in case you reference documents

or DTDs outside a corporate firewall

PROCEDURE setHttpProxy(machinename VARCHAR2,

port VARCHAR2 := '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;

Trang 31

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);

the in-memory DOM Document representation of the parsed XML

Call freeDocument( ) when you're done using the document returned by the function

- FUNCTION parse(xml VARCHAR2) RETURN xmldom.DOMDocument IS

Trang 33

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 to, and retrieving them from, an xml_documents table A database trigger on the xml_documents table manages a timestamp column indicating the last time a new XML document was saved in the table Each XML document is saved as a CLOB and is accessed by a document name that serves

as the primary key for the document For convenience, you can retrieve an existing document in the table by using:

Trang 34

Retrieves a CLOB

The xmldoc.save method uses the xml helper package described in the previous section to

xml.parse the document being saved, checking it for XML well-formedness in the process Any well-formedness errors prevent the document from being saved If the document is well-formed, the code uses the xmldom.writeToClob method to save the XML document in the

xml_documents table's xmldoc CLOB column

If the documents you are saving contain external references to URLs outside your corporate firewall, you'll need to call xml.setHttpProxy once in your current database session before using the xmldoc routines

Here is the source code for the xmldoc package:

CREATE OR REPLACE PACKAGE xmldoc AS

Save an XML document (parsing it first if necessary) into the

xml_documents table with a given document name

PROCEDURE save(name VARCHAR2,

xmldoc VARCHAR2,

docommit BOOLEAN := TRUE);

PROCEDURE save(name VARCHAR2,

xmldoc CLOB,

docommit BOOLEAN := TRUE);

PROCEDURE save(name VARCHAR2,

xmldoc 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 document as a CLOB by name from the xml_documents table

FUNCTION getAsCLOB(name VARCHAR2) RETURN CLOB;

Get an XML document as a VARCHAR2 by name from the xml_documents table FUNCTION getAsText(name VARCHAR2) RETURN VARCHAR2;

Remove an XML document by name from the xml_documents table

Trang 35

PROCEDURE remove(name VARCHAR2, docommit BOOLEAN := TRUE); Test if a named document exists in the xml_documents table

FUNCTION docExists(name VARCHAR2) RETURN BOOLEAN;

END;

CREATE OR REPLACE PACKAGE BODY xmldoc AS

FUNCTION get(name VARCHAR2, createNew BOOLEAN) RETURN CLOB IS

Trang 36

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);

PROCEDURE save(name VARCHAR2,xmldoc CLOB,docommit BOOLEAN:=TRUE) IS

c CLOB := get(name, createNew=>TRUE);

PROCEDURE save(name VARCHAR2,xmldoc BFILE,docommit BOOLEAN:=TRUE) IS

c CLOB := get(name, createNew=>TRUE);

PROCEDURE save(name VARCHAR2,xmldoc xmldom.DOMDocument,docommit BOOLEAN:=TRUE) IS

c CLOB := get(name, createNew=>TRUE);

BEGIN

Trang 37

xmldom.writeToClob(xmldoc,c);

IF docommit THEN commit; END IF;

END;

PROCEDURE remove(name VARCHAR2,docommit BOOLEAN := TRUE) IS

c CLOB := get(name, createNew=>FALSE);

BEGIN

DELETE FROM xml_documents WHERE docname = name;

IF docommit THEN commit; END IF;

A.2.3 The xpath Package

The xpath package provides four key functions used to exploit XPath expressions on in-memory XML documents:

Selects a list of nodes matching an XPath expression

Here is the source code for the xpath package:

CREATE OR REPLACE PACKAGE xpath AS

Return the value of an XPath expression, optionally normalizing whitespace FUNCTION valueOf(doc xmldom.DOMDocument,

Trang 38

xpath VARCHAR2,

normalize BOOLEAN:=FALSE) RETURN VARCHAR2;

FUNCTION valueOf(node xmldom.DOMNode,

xpath VARCHAR2,

normalize BOOLEAN:=FALSE) RETURN VARCHAR2;

FUNCTION valueOf(doc VARCHAR2,

xpath VARCHAR2,

normalize BOOLEAN := FALSE) RETURN VARCHAR2;

FUNCTION valueOf(doc CLOB,

xpath VARCHAR2,

normalize BOOLEAN := FALSE) RETURN VARCHAR2;

Test whether an XPath predicate is true

FUNCTION test(doc xmldom.DOMDocument,xpath VARCHAR2) RETURN BOOLEAN; FUNCTION test(node xmldom.DOMNode, xpath VARCHAR2) RETURN BOOLEAN; FUNCTION test(doc VARCHAR2, xpath VARCHAR2) RETURN BOOLEAN; FUNCTION test(doc CLOB, xpath VARCHAR2) RETURN BOOLEAN;

Extract an XML fragment for set of nodes matching an XPath pattern optionally normalizing whitespace (default is to normalize it)

FUNCTION extract(doc xmldom.DOMDocument,

xpath VARCHAR2:='/',

normalize BOOLEAN:=TRUE) RETURN VARCHAR2;

FUNCTION extract(doc VARCHAR2,

xpath VARCHAR2 := '/',

normalize BOOLEAN := TRUE) RETURN VARCHAR2;

FUNCTION extract(doc CLOB,

xpath VARCHAR2 := '/',

normalize BOOLEAN := TRUE) RETURN VARCHAR2;

Select a list of nodes matching an XPath pattern

Note: DOMNodeList returned has a zero-based index

FUNCTION selectNodes(doc xmldom.DOMDocument,

xpath VARCHAR2) RETURN xmldom.DOMNodeList;

FUNCTION selectNodes(node xmldom.DOMNode,

xpath VARCHAR2) RETURN xmldom.DOMNodeList;

Trang 39

FUNCTION selectNodes(doc VARCHAR2,

xpath VARCHAR2) RETURN xmldom.DOMNodeList;

FUNCTION selectNodes(doc CLOB,

xpath VARCHAR2) RETURN xmldom.DOMNodeList;

END;

CREATE OR REPLACE PACKAGE BODY xpath AS

"Casts" a DOMDocument as a DOMNode

FUNCTION toNode(doc xmldom.DOMDocument) RETURN xmldom.DOMNode IS

BEGIN RETURN xmldom.makeNode(doc); END;

- Removes extraneous whitespace from a string

Translates CR, LF, and TAB to spaces, then leaves only a single space between characters

- FUNCTION normalizeWS( v VARCHAR2 )

RETURN VARCHAR2 IS

result VARCHAR2(32767);

BEGIN

result := RTRIM(LTRIM(TRANSLATE(v,CHR(13)||CHR(8)||CHR(10),' '))); WHILE (INSTR(result,' ') > 0) LOOP

document order Passing an XPath of '/' matches the single root node and so the entire document is serialized to XML markup If the

normalizeWhitespace is set to TRUE (the default) then the string is stripped of extraneous whitespace before being returned

- FUNCTION selectAndPrint(doc xmldom.DOMDocument,xpath VARCHAR2,

normalizeWhitespace BOOLEAN := TRUE)

RETURN VARCHAR2 IS

retval VARCHAR2(32767);

result VARCHAR2(32767);

curNode xmldom.DOMNode;

Trang 40

The "extract" functions parse the inbound document if necessary

and use selectAndPrint to extract the XML markup for the nodes

matching the XPath expression passed in If the normalize parameter

is TRUE, extraneous whitespace is removed

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

TỪ KHÓA LIÊN QUAN