|

Buy
Professional ASP XML
Generating the XSL
Now let's start looking at the process of generating the XSL
file.
Normal XML rules apply. The XML generated by our ASP page must
be well-formed, which means that case matters.
There are two approaches we could use in order to meet our
goal of creating the XSL:
q We could build a string
q We could create an instance of the XML DOM, build a result
tree and write out the XML as a string
Either approach is valid for our needs. The first is simpler,
and may be faster, but it is a limited solution. Should we wish
to revisit this application at some point in the future and
extend its functionality, our options would very restricted.
Furthermore, we would be limited to a linear building process,
and it would be cumbersome to dynamically modify any part of
the result string that had already been built. It would be difficult,
for example, to add the capability of converting an attribute
in the source document to an element in the result. By taking
the XML DOM approach, all of the capabilities of the DOM are
available to us, and we are not limited to a sequential result.
Plus, it's more of an XML-purist approach to the problem.
So, we will need two instances of the XML DOM. The first will
contain the result tree we will be building, whose XML source
will ultimately become our return value, and the second instance
will host the XML translation document that will drive the creation
process.
As you're looking through the discussion of how this ASP page
works, you may find it useful to refer to the end result, which
is shown here as rendered in Internet Explorer 5, with the color
coding and indentation provided by IE's default internal style
sheet.
If you download the source code for this book and look at the
interpreter.php file in your browser, this is what you should
see.
As is always the case when we use an ASP to generate XML, we
need to set the response type:
<%
Response.ContentType = "text/xml"
Response.Expires = 0
dim result
dim interpreter
dim oNodes
Next we will create our required two instances of the XML DOM,
and load in the interpreter.xml file (our mapping file):
Set result = Server.CreateObject("Microsoft.XMLDOM")
Set interpreter = Server.CreateObject("Microsoft.XMLDOM")
interpreter.async = false
'// load the definition file
sSource = Server.MapPath("interpreter.xml")
interpreter.load(sSource)
'// did the XML file load OK?
If interpreter.parseError.errorCode <> 0 Then
msg = "<msg><gen>Error loading INTERPRETER
data file.</gen>"
msg = msg & "<br>Description: " &
interpreter.parseError.reason &
"</br>"
msg = msg & "<br>Source text: " &
interpreter.parseError.srcText &
"</br></msg>"
Response.Write msg
End If
...
Note that as this code is running server-side, we need to provide
a physical path to the XML file that we are loading, which is
done by using Server.MapPath. We set the async property of the
interpreter file to false, as we cannot process anything until
this file is completely loaded. The async property of the result
tree is irrelevant.
Next we extract all of the <xlat> nodes from our definition
tree:
Set oNodes = interpreter.documentElement.selectNodes("//xlat")
Now we are ready to start populating our result tree. The first
step is to add the node that identifies this XML document as
a style sheet:
'// add a node to the result tree for the stylesheet declaration
Set oNewNode = result.createNode("element","xsl:stylesheet",
_
"http://www.w3.org/TR/WD-xsl")
result.appendChild(oNewNode)
Then we set the root element, the stylesheet declaration, as
follows:
'// the stylesheet declaration is the outermost grouping tag.
It is the root
'// element and parent to all other elements
Set root = result.documentElement
If you refer back to the IE5 view of the XSL shown in the previous
figure, you'll see that the next entry is <xsl:template match="/">,
which we create as follows:
'// create the XSL node
Set oTemp = result.createNode("element","xsl:template",
_
"http://www.w3.org/TR/WD-xsl")
oTemp.setAttribute "match", "/"
root. appendChild(oTemp)
Rather than hard-coding the names of the root document and
the item of the translation result (<shipments> and <shipment>
in our example), we extract those tag names from the definition
file. This is based on the assumption that the root element
of the definition file will also be the root element of the
translation result:
'// name of the container tag (eg: "shipments")
nodeName = interpreter.documentElement.firstChild.nodeName
Set oContainer = result.createNode("element", _
interpreter.documentElement.nodeName,"")
oTemp.appendChild(oContainer)
Note that we have created the oContainer variable, which represents
the root element (shipments) of the translated result.
Now we need to add a line to our XSL result tree that when
processed will tell the XSL to iterate through all instances
of the children (shipment) of that root. The following code
will create an element containing <xsl:for-each select="//shipment">
and append it to the result tree:
Set oLoop = result.createNode("element","xsl:for-each",
_
"http://www.w3.org/TR/WD-xsl")
oLoop.setAttribute "select", "//" &
nodeName
oContainer.appendChild(oLoop)
Next we create an entry for the contained item (that is <shipment>)
and append it to the result tree:
Set oLoopParent = result.createNode("element",nodeName,
"")
oLoop.appendChild(oLoopParent)
Now we get to the real work. In this section of the code, we
iterate through each of the <xlat> mapping elements. For
each one, we create an element using the name attribute of the
<out> element, and an <xsl:value-of> from the select
attribute from the <in> element. These items are added
to the result tree.
An example of one of these would be:
<shippedby><xsl:value-of select="carrier"/></shippedby>
For Each oNode in oNodes
Set oNewNode = result.createNode("element", _
oNode.selectSingleNode("out").getAttribute("name"),
"")
Set oSelect = result.createNode("element",_
"xsl:value-of","http://www.w3.org/TR/WD-xsl")
oSelect.setAttribute "select",oNode.selectSingleNode("in").getAttribute("name")
oNewNode.appendChild(oSelect)
oLoopParent.appendChild(oNewNode)
Next
Finally, we need to add the apply-templates node:
Set oNode = result.createNode("element","xsl:apply-templates",
"http://www.w3.org/TR/WD-xsl")
oTemp.appendChild(oNode)
We have now completely built our result tree, and we return
it to the calling application (which could be a browser, a script,
an XML file, etc):
Response.Write result.xml
%>
If you are considering adapting this procedure for your own
project, then the first stage should be to create an XSL file
that gets the data from the XML document. This way you can get
the display right before you start writing your interpretation
code.
The Test Page
Now let's see this all at work by looking at the test page,
which is included in the source download as default.php. We
will use the JavaScript alert() function to display the XML
because if we show it in the browser the tags will not be visible.
When it loads, the test page will invoke the init() function.
It will create two instances of the XML DOM, one for the XML
source document, and the second for the dynamic XSL file. The
last thing it does is apply the XSL to the source XML, and saves
the resulting string in the "processed" variable.
This is our translated XML. The full code is shown here:
<html>
<head>
<link REL="stylesheet" TYPE="text/css"
HREF="list.css">
</head>
<body>
<hr color=red>
<button onclick='alert(source.xml);'>1. Show incoming.xml</button>
<button onclick='alert(dynstyle.xml);'>2. Show dynstyle.xsl</button>
<button onclick='alert(processed);' id=button1 name=button1>
3. Show Translation
</button><br>
<hr color=red>
<script FOR="window" EVENT="onload">
init();
</script>
<script>
var source;
var sourceName = "incoming.xml";
var dynstyle;
var dynstyleName = "interpreter.php";
var processed = "";
function init(){
// Do init stuff. Called by the parent frame.
source = new ActiveXObject('Microsoft.XMLDOM');
source.async = false;
source.load(sourceName);
// did the XML file load OK?
if (source.parseError.errorCode != 0){
msg = 'Error loading SOURCE file.'
msg += '\nDescription: ' + source.parseError.reason
msg += '\nSource text: ' + source.parseError.srcText
}
root = source.documentElement;
dynstyle = new ActiveXObject('Microsoft.XMLDOM');
dynstyle.async = false;
dynstyle.load(dynstyleName)
// did the XML file load OK?
if (dynstyle.parseError.errorCode != 0){
msg = 'Error loading DYNSTYLE file.'
msg += '\nDescription: ' + dynstyle.parseError.reason
msg += '\nSource text: ' + dynstyle.parseError.srcText
}
processed = source.transformNode(dynstyle)
}
</script>
</body>
</html>
I have provided three buttons on the test page that show the
three entities that make up this example:
q Button 1 shows the original un-translated source document
(incoming.xml)
q Button 2 shows the dynamically-generated XSL returned as
a result from interpreter.php
q Button 3 shows the translated version of the source document,
after the style has been applied to it.
How it Works
The following screen shot shows the un-translated source document:
This screen shot shows our dynamically generated XSL:
This final screen shot shows the result of the translation:
Summary
In this chapter, we have seen a way to use ASP to generate an
XSL file dynamically. We did this by using an ASP page to create
an instance of the XML DOM and employing DOM methods to build
the result tree. The information needed to build the result
tree came from the contents of an XML file. A test web page
then used the dynamic XSL to translate from one XML structure
to another.
So now we have finished our discussion on styling XML for our
web browsers. We will use XSL frequently as we progress through
this book. In the next chapter we shall move on to storing and
retrieving XML data from databases using ActiveX Data Objects
(ADO).
back
| Contents
Buy
Professional ASP XML
|