Tải bản đầy đủ (.pdf) (50 trang)

Tài liệu XML by Example- P7 doc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (502.08 KB, 50 trang )

var name = form.name.value,
dollars = form.dollarsamount.value,
euros = form.eurosamount.value,
productList = form.productlist;
// creates the various objects required
var dollarsPrice = new Price(dollars,”usd”),
eurosPrice = new Price(euros,”eur”),
prices = new Array(dollarsPrice,eurosPrice),
product = new Product(name,prices);
// arrays are zero-based so products.length points
// to one past the latest product
// JavaScript automatically allocates memory
var pos = products.length;
products[pos] = product;
var option = new Option(name,pos);
productList.options[productList.length] = option;
}
function deleteProduct(form)
{
var productList = form.productlist,
pos = productList.selectedIndex;
if(pos != -1)
{
var product = productList.options[pos].value;
productList.options[pos] = null;
products[product] = null;
}
}
function exportProduct(form)
{
285


Creating Documents Without DOM
continues
11 2429 CH09 11/12/99 1:02 PM Page 285
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
form.output.value = makeXML();
}
function send()
{
var http = new ActiveXObject(“Microsoft.XMLHTTP”);
http.open(“POST”,” />http.setRequestHeader(“Content-type”,”application/xml”);
http.send(“value=” + makeXML());
document.open();
document.write(http.responseText);
}
function makeXML()
{
var xmlCode = “”;
var i;
for(i = 0;i < products.length;i++)
if(products[i] != null)
xmlCode += products[i].toXML();
return element(“products”,””,xmlCode);
}
function resetAll(form,document)
{
priceList = null;
form.output.value = “”;
}
function element(name,attributes,content)
{

var result = “<” + name;
if(attributes != “”)
result += “ “ + attributes;
result += “>”;
286
Chapter 9: Writing XML
Listing 9.6: continued
11 2429 CH09 11/12/99 1:02 PM Page 286
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
result += content;
result += “</” + name + “>\r”;
return result;
}
function escapeXML(string)
{
var result = “”,
i,
c;
for(i = 0;i < string.length;i++)
{
c = string.charAt(i);
if(c == ‘<’)
result += “&lt;”;
else if(c == ‘&’)
result += “&amp;”;
else
result += c;
}
return result;
}

// declares two JavaScript objects
// product object
function Product(name,prices)
{
this.name = name;
this.prices = prices;
this.toXML = product_toXML;
}
function product_toXML()
{
var result = element(“name”,””,escapeXML(this.name)),
287
Creating Documents Without DOM
continues
11 2429 CH09 11/12/99 1:02 PM Page 287
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
i;
for(i = 0;i < this.prices.length;i++)
result += this.prices[i].toXML();
return element(“product”,””,result);
}
// price object
function Price(amount,currency)
{
this.amount = amount;
this.currency = currency;
this.toXML = price_toXML;
}
function price_toXML()
{

return element(“price”,
“currency=\”” + this.currency + “\””,
escapeXML(this.amount));
}
Because this application does not use DOM, it works with browsers that
have no XML support (obviously, they need to support JavaScript), such as
Netscape 4. Figure 9.3 shows the result in Netscape.
A Non-DOM Data Structure
This application is radically different from the other applications intro-
duced in this chapter. Internally, the application does not use XML, but
uses its own data structure instead. In other words, it does not create
Element
objects; it creates
Product
and
Price
JavaScript objects.
In JavaScript, an object constructor is simply a function that sets the object
properties. A method is a property that is assigned a function.
288
Chapter 9: Writing XML
Listing 9.6: continued
OUTPUT
11 2429 CH09 11/12/99 1:02 PM Page 288
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Figure 9.3: The result in Netscape
In this example, the constructor for
Product
declares two properties (
name

and
prices
) and one method (
toXML
).
function Product(name,prices)
{
this.name = name;
this.prices = prices;
this.toXML = product_toXML;
}
These objects are created with the
new
operator like built-in JavaScript
objects:
var product = new Product(name,prices);
JavaScript objects are used like built-in objects:
xmlCode += products[i].toXML();
Writing XML
The
Product
and
Price
objects are XML-aware because they know how to
save (serialize) themselves as XML objects through the
toXML()
function.
The
makeXML()
function is trivial: It iterates over the list of products calling

the
toXML()
function. It wraps the result in a
products
element:
function makeXML()
{
var xmlCode = “”;
289
Creating Documents Without DOM
EXAMPLE
11 2429 CH09 11/12/99 1:02 PM Page 289
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
var i;
for(i = 0;i < products.length;i++)
if(products[i] != null)
xmlCode += products[i].toXML();
return element(“products”,””,xmlCode);
}
Notice that this approach is recursive.
Product
implements its
toXML()
method partly by serializing the list of
Price
and wrapping it in a
product
element.
function product_toXML()
{

var result = element(“name”,””,escapeXML(this.name)),
i;
for(i = 0;i < this.prices.length;i++)
result += this.prices[i].toXML();
return element(“product”,””,result);
}
function price_toXML()
{
return element(“price”,
“currency=\”” + this.currency + “\””,
escapeXML(this.amount));
}
XML is a convenient format because elements can nest in a way that is
very similar to how objects are referenced by other objects.
Hiding the Syntax
This application needs to know very little about the XML syntax. Its knowl-
edge is completely encapsulated in two functions—
element()
and
escapeXML()
.
1. element()
is in charge of the tagging. Again, the core XML syntax
function is simple and it shows in this function.
function element(name,attributes,content)
{
var result = “<” + name;
290
Chapter 9: Writing XML
EXAMPLE

11 2429 CH09 11/12/99 1:02 PM Page 290
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
if(attributes != “”)
result += “ “ + attributes;
result += “>”;
result += content;
result += “</” + name + “>\r”;
return result;
}
2. escapeXML()
ensures that the angle bracket and ampersand characters
are escaped. These characters are not allowed in the text of an ele-
ment.
function escapeXML(string)
{
var result = “”,
i,
c;
for(i = 0;i < string.length;i++)
{
c = string.charAt(i);
if(c == ‘<’)
result += “&lt;”;
else if(c == ‘&’)
result += “&amp;”;
else
result += c;
}
return result;
}

Creating Documents from Non-XML Data Structures
For most applications, it is easy to write an XML generator. Indeed,
the core XML syntax (essentially composed of tags) is not complex.
Furthermore, XML elements nest in a way that is very convenient for
object-oriented applications.
Typically, creating documents from non-XML data structures is more effi-
cient than the DOM-based approach because the application doesn’t have to
duplicate its data structure. Figure 9.4 compares the two approaches.
291
Creating Documents from Non-XML Data Structures
EXAMPLE
11 2429 CH09 11/12/99 1:02 PM Page 291
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
TIP
So, when do you use DOM and when do you write your own generator? I find that
DOM is ideal for modifying existing documents. In most other cases, I prefer my own
generator.
292
Chapter 9: Writing XML
Figure 9.4: Comparing DOM with an ad hoc generator
Doing Something with the XML Documents
Now that you can create XML documents, you probably want to do some-
thing more involved than display the XML code in an HTML form. In most
cases, the application can either save the document to a file or send it to a
server.
✔ This section looks briefly at your options to save the document or send it to the server.
We will revisit this topic in Chapter 12, “Putting It All Together: An e-Commerce Example,”
(page 381).
Sending the Document to the Server
There are two options to send the document to the server. You can place the

XML document in an HTML form and have it sent along with the form, you
can use a JavaBean or an ActiveX control to post the XML document to the
Web server.
1. Sending the XML document in a form is the most portable approach.
Because you already create the XML document in a form, this is easy
to do. The
FORM
tag needs an
ACTION
attribute and the
INPUT
field must
be changed from
BUTTON
to
SUBMIT
. You might also want to change the
TEXTAREA
in a
HIDDEN
field so XML does not appear onscreen:
11 2429 CH09 11/12/99 1:02 PM Page 292
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Listing 9.8: HTML Form to Send the Document
<FORM NAME=”controls” ACTION=”/Dump” METHOD=”POST”>
Product name: <INPUT TYPE=”TEXT” NAME=”name”>
Price (Dollars): <INPUT TYPE=”TEXT”
NAME=”dollarsamount” SIZE=”7”>
Price (Euros): <INPUT TYPE=”TEXT”
NAME=”eurosamount” SIZE=”7”><BR>

<SELECT NAME=”productlist” SIZE=”5” WIDTH=”250”>
</SELECT><BR>
<INPUT TYPE=”BUTTON” VALUE=”Add”
ONCLICK=”addProduct(controls)”>
<INPUT TYPE=”BUTTON” VALUE=”Delete”
ONCLICK=”deleteProduct(controls)”>
<INPUT TYPE=”SUBMIT” VALUE=”Send in XML”
ONCLICK=”exportProduct(controls)”>
<INPUT TYPE=”BUTTON” VALUE=”Clear”
ONCLICK=”output.value=’’”><BR>
<!-- there must be one character in the text area -->
<INPUT TYPE=”HIDDEN” NAME=”output” VALUE=””>
</FORM>
The Web server will receive the XML document in a parameter called “out-
put.” You would have to write a servlet or a CGI script to retrieve the docu-
ment on the Web server. The beauty of this approach is that the document
is returned in a form so the servlet simply accesses form parameters to
retrieve the XML document.
✔ The section “Viewer and Editor” in Chapter 12 (page 444) shows such a servlet.
CAUTION
This example uses the Dump service that comes standard with Jetty, the Web server.
Dump replies with a document that contains whatever it originally received. It is conve-
nient for testing.
If you don’t use Jetty, you will need to write your own servlet to accept the XML docu-
ment.
✔ The section “Servlet Engine” in Appendix A explains how to install Jetty (page 460).
Alternatively, you can post the data directly to the Web server, without
going through a form. This method has the added benefit of not changing
the current page. However, you have to go through an ActiveX object
293

Doing Something with the XML Documents
11 2429 CH09 11/12/99 1:02 PM Page 293
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
(Internet Explorer), a plug-in (all browsers), or a JavaBean (all browsers,
all platforms).
2. Internet Explorer 5.0 ships with XMLHTTP, an ActiveX control that
can send XML documents from JavaScript. Listing 9.9 shows how to
use XMLHTTP.
Listing 9.9: Posting the Result on a Web Site
function send()
{
var http = new ActiveXObject(“Microsoft.XMLHTTP”);
http.open(“POST”,” />http.setRequestHeader(“Content-type”,”application/xml”);
http.send(makeXML());
document.open();
document.write(http.responseText);
}
The ActiveX object has the following methods:

open(protocol,url,asynchronous)
connects to a
url
. Set the
protocol
to
POST
. Set
asynchronous
to
false

to send synchronously.

setRequestHeader(keyword,value)
adds a new
keyword
in the header of
the document; you must use this function to set the content-type.

send(data)
posts the
data
to the server.
You need to change the “Send in XML” button in Listing 9.9 to call this
function:
<INPUT TYPE=”SUBMIT” VALUE=”Send in XML” ONCLICK=”send()”>
Again, you need a servlet or CGI script on the server to receive the XML
document.
The URL
/>points the Dump ser-
vice on my machine. You will need to change this URL to your Web server.
Listing 9.10 is a typical response from the server.
TIP
Jetty’s Dump returns an HTML document that contains the POST parameters. Choose
“View Source” in your browser options to see the XML document.
Listing 9.10: XML Document Returned by the Server
<products><product><name>XML Editor</name>
<price currency=”usd”>499.00</price>
<price currency=”eur”>475.00</price>
294
Chapter 9: Writing XML

EXAMPLE
OUTPUT
11 2429 CH09 11/12/99 1:02 PM Page 294
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
</product>
<product><name>DTD Editor</name>
<price currency=”usd”>199.00</price>
<price currency=”eur”>190</price>
</product>
<product><name>XML Book</name>
<price currency=”usd”>19.99</price>
<price currency=”eur”>19.00</price>
</product>
<product><name>XML Training</name>
<price currency=”usd”>699.00</price>
<price currency=”eur”>666.00</price>
</product>
</products>
Saving the Document
JavaScript applications cannot access the local hard disk unless they have
been signed. Therefore, it is not common to save the XML in a file on a
browser.
However, on the server, you often want to save XML documents. If you cre-
ated the file with your own generator, you save it like any other file.
When creating a document with a Microsoft DOM parser, you use a
Microsoft-specific extension to save the document. Microsoft parser sup-
ports the
save()
function.
However, as I have just explained, this extension does not work on the

browser. It is therefore only useful when writing CGI scripts or ASP pages.
The example in Listing 9.11 shows how to save a file from JavaScript in an
ASP server.
Listing 9.11: Saving the XML Document
<%
var xmldoc = new ActiveXObject(“Microsoft.XMLDOM”);
// creates the XML document here
// ...
xmldoc.save(Server.MapPath(“request.xml”));
%>
295
Doing Something with the XML Documents
11 2429 CH09 11/12/99 1:02 PM Page 295
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
NOTE
To create an XML parser from ASP, you cannot use an XML island. Instead create the
XML parser directly as an ActiveXObject as in
var xmldoc = new ActiveXObject(“Microsoft.XMLDOM”);
This is equivalent to creating an XML island on a browser.
Writing with Flexibility in Mind
One of the major advantages of XML is that it is extensible. Anyone can
create a tagging language with tags specific to the application.
On the other hand, it means applications must be able to support different
DTDs. For example, your company can have its own DTDs for internal
exchange. However, when exchanging documents with other companies, you
may have to use another DTD.
There are also so-called standard DTDs developed by various standardiza-
tion committees. In fact, developing DTDs has become a favorite activity in
standard bodies lately, so expect more in the future. Unfortunately, so many
committees are actively developing standards that you may have to support

several incompatible standards.
There are essentially two solutions to this problem. Either you define sev-
eral
toXML()
functions, one for each DTD that you want to support, or you
turn to XSLT.
In most cases, I would advocate using XSLT. It is a waste of time to write
as many functions as there are DTDs. XSLT is also more flexible because
you don’t have to write code to add new DTDs or when a DTD changes (and
it happens more often than you might think).
Supporting Several DTDs with XSLT
Listings 9.12 and 9.13 show how to use XSLT to support several DTDs.
The user chooses the DTD from a list box. Unlike the previous version, this
version uses the XSL processor of Internet Explorer. It will not run on
Netscape.
TIP
If you need to support both browsers, you can replace the Internet Explorer XSL proces-
sor with LotusXSL.
LotusXSL comes with several examples that show how to use it in a browser. However,
it is not as stable as using the built-in XSL processor. If at all possible, stick to Internet
Explorer.
296
Chapter 9: Writing XML
EXAMPLE
11 2429 CH09 11/12/99 1:02 PM Page 296
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Listing 9.12: The HTML Code
<HTML>
<HEAD>
<TITLE>Price List Editor</TITLE>

<SCRIPT LANGUAGE=”JavaScript” SRC=”createlist.js”></SCRIPT>
</HEAD>
<BODY>
<CENTER>
<FORM NAME=”controls”>
Product name: <INPUT TYPE=”TEXT” NAME=”name”>
Price (Dollars): <INPUT TYPE=”TEXT”
NAME=”dollarsamount” SIZE=”7”>
Price (Euros): <INPUT TYPE=”TEXT”
NAME=”eurosamount” SIZE=”7”><BR>
<SELECT NAME=”productlist” SIZE=”5” WIDTH=”250”>
</SELECT><BR>
<INPUT TYPE=”BUTTON” VALUE=”Add”
ONCLICK=”addProduct(controls)”>
<INPUT TYPE=”BUTTON” VALUE=”Delete”
ONCLICK=”deleteProduct(controls)”>
<INPUT TYPE=”BUTTON” VALUE=”Export to XML”
ONCLICK=”exportProduct(controls,xml,xslt)”>
<SELECT NAME=”format”>
<OPTION VALUE=”default” SELECTED>products</OPTION>
<OPTION VALUE=”external”>price-list</OPTION>
</SELECT>
<INPUT TYPE=”BUTTON” VALUE=”Clear”
ONCLICK=”output.value=’’”><BR>
<!-- there must be one character in the text area -->
<TEXTAREA NAME=”output” ROWS=”12” COLS=”50” READONLY>
</TEXTAREA>
</FORM>
</CE_TER>
<xml id=”xml”></xml>

<xml id=”xslt” src=”convert.xsl”></xml>
</BODY>
</HTML>
297
Writing with Flexibility in Mind
11 2429 CH09 11/12/99 1:02 PM Page 297
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Listing 9.13: The JavaScript Code
var products = new Array();
function addProduct(form)
{
// collects data from the form
var name = form.name.value,
dollars = form.dollarsamount.value,
euros = form.eurosamount.value,
productList = form.productlist;
// creates the various objects required
var dollarsPrice = new Price(dollars,”usd”),
eurosPrice = new Price(euros,”eur”),
prices = new Array(dollarsPrice,eurosPrice),
product = new Product(name,prices);
// arrays are zero-based so products.length points
// to one past the latest product
// JavaScript automatically allocates memory
var pos = products.length;
products[pos] = product;
var option = new Option(name,pos);
productList.options[productList.length] = option;
}
function deleteProduct(form)

{
var productList = form.productlist,
pos = productList.selectedIndex;
if(pos != -1)
{
var product = productList.options[pos].value;
productList.options[pos] = null;
products[product] = null;
298
Chapter 9: Writing XML
11 2429 CH09 11/12/99 1:02 PM Page 298
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
}
}
function exportProduct(form,xml,xslt)
{
var selected = form.format.selectedIndex,
format = form.format.options[selected].value;
if(format == “default”)
form.output.value = makeXML();
else
{
var xmlDoc = makeXML();
xml.async = false;
// passes an XML string to the parser
xml.loadXML(xmlDoc);
form.output.value = xml.transformNode(xslt.XMLDocument);
}
}
function send()

{
var http = new ActiveXObject(“Microsoft.XMLHTTP”);
http.open(“POST”,” />http.setRequestHeader(“Content-type”,”application/xml”);
http.send(“value=” + makeXML());
document.open();
document.write(http.responseText);
}
function makeXML()
{
var xmlCode = “”;
var i;
for(i = 0;i < products.length;i++)
if(products[i] != null)
299
Writing with Flexibility in Mind
continues
11 2429 CH09 11/12/99 1:02 PM Page 299
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
xmlCode += products[i].toXML();
return element(“products”,””,xmlCode);
}
function resetAll(form,document)
{
priceList = null;
form.output.value = “”;
}
function element(name,attributes,content)
{
var result = “<” + name;
if(attributes != “”)

result += “ “ + attributes;
result += “>”;
result += content;
result += “</” + name + “>\r”;
return result;
}
function escapeXML(string)
{
var result = “”,
i,
c;
for(i = 0;i < string.length;i++)
{
c = string.charAt(i);
if(c == ‘<’)
result += “&lt;”;
else if(c == ‘&’)
result += “&amp;”;
else
result += c;
}
300
Chapter 9: Writing XML
Listing 9.13: continued
11 2429 CH09 11/12/99 1:02 PM Page 300
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
return result;
}
// declares two JavaScript objects
// product object

function Product(name,prices)
{
this.name = name;
this.prices = prices;
this.toXML = product_toXML;
}
function product_toXML()
{
var result = element(“name”,””,escapeXML(this.name)),
i;
for(i = 0;i < this.prices.length;i++)
result += this.prices[i].toXML();
return element(“product”,””,result);
}
// price object
function Price(amount,currency)
{
this.amount = amount;
this.currency = currency;
this.toXML = price_toXML;
}
function price_toXML()
{
return element(“price”,
“currency=\”” + this.currency + “\””,
this.amount);
}
301
Writing with Flexibility in Mind
11 2429 CH09 11/12/99 1:02 PM Page 301

Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
The application outputs a default XML format. The style sheet in Listing
9.14 does the conversion. Obviously, it is an Internet Explorer style sheet.
As explained in Chapter 5, “XSL Transformation,” this style sheet is not
strictly compliant with the standard but it would not take too much work
to adapt it.
Listing 9.14: The Style Sheet
<?xml version=”1.0” encoding=”ISO-8859-1”?>
<!-- I.E. 5.0 style sheet: no built-in rule and old URI-->
<xsl:stylesheet xmlns:xsl=” /><xsl:template match=”/”>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match=”products”>
<price-list>
<xsl:apply-templates/>
</price-list>
</xsl:template>
<xsl:template match=”product”>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match=”price”>
<line>
<xsl:attribute name=”name”><xsl:value-of select=”../name”/>
➥</xsl:attribute>
<xsl:attribute name=”price”><xsl:value-of select=”.”/>
➥</xsl:attribute>
<xsl:attribute name=”currency”>
➥<xsl:value-of select=”@currency”/></xsl:attribute>
</line>
</xsl:template>

</xsl:stylesheet>
302
Chapter 9: Writing XML
11 2429 CH09 11/12/99 1:02 PM Page 302
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Figures 9.5 and 9.6 illustrate the difference between the two DTDs. Figure
9.5 is the structure created so far—it is a complex structure with several
levels of nesting. Figure 9.6, on the other hand, has a flat structure.
303
Writing with Flexibility in Mind
Figure 9.5: The default structure Figure 9.6: The new structure
Figures 9.7 and 9.8 show the difference when selecting one or the other out-
put format in the browser.
OUTPUT
Figure 9.7: Default output format Figure 9.8: New output format
Calling XSLT
The major difference between this application and the previous one is the
exportProduct()
function.
exportProduct()
calls
makeXML()
to generate the
XML document. Depending on the user choice, it may apply an XSLT style
sheet to the result.
function exportProduct(form,xml,xslt)
{
var selected = form.format.selectedIndex,
format = form.format.options[selected].value;
if(format == “default”)

form.output.value = makeXML();
EXAMPLE
11 2429 CH09 11/12/99 1:02 PM Page 303
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
else
{
var xmlDoc = makeXML();
xml.async = false;
// passes an XML string to the parser
xml.loadXML(xmlDoc);
form.output.value = xml.transformNode(xslt.XMLDocument);
}
}
Unfortunately, the DOM standard does not specify how to apply an XSLT
style sheet to a document. Again, you can use a browser-specific extension.
For Internet Explorer, the XSL processor is called by the
transformNode()
method.
The XSLT style sheet was loaded in a separate XML island.
<xml id=”xml”></xml>
<xml id=”xslt” src=”convert.xsl”></xml>
Which Structure for the Document?
If your application supports several DTDs, you may wonder which one to
use as the default DTD. Experience shows that it pays to be dumb when
designing this default DTD.
I like to define a DTD that is very similar to my object structure. So, if the
application has
Product
and
Price

objects, I create two elements:
product
and
price
.
There are two main advantages to designing a DTD that is close to the
internal data structure:
• It is easy to generate the XML document.
• The resulting document is as expressive as the internal data struc-
ture.
XSLT Versus Custom Functions
XSLT has been designed specifically to convert XML documents. It offers a
simple solution to cleanly separate the DTD from the application code. This
separation of roles offers many advantages:
• If the format changes, you don’t have to change your application, only
the style sheet.
304
Chapter 9: Writing XML
11 2429 CH09 11/12/99 1:02 PM Page 304
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.

×