Using XSL and XSLT Transformations


Let's come back to a topic first discussed in Chapter 8. There, you saw how easy it is to perform an XSL or XSLT transformation against an XML document using the new XslTransform object. However, we only applied it to two disk files (an XML document and a style sheet) by specifying the paths to these files.

You can use the XslTransform object to perform transformations when the document is not actually a disk file. This could well be the case in an application that processes XML. For example, it could be referenced by an XmlTextReader , or stored in the XmlDocument object returned by a web service or business component, or even pointed to by an existing XPathNavigator . And you might not want the results to be written to disk as a file “ you might need them as a String or a StringBuilder object. The next example attempts to demonstrate several of these scenarios.

Note

In version 1.1, Microsoft suggests an updated approach to loading stylesheets that are not fully trusted. See the Loading Stylesheets and Schemas with an XmlResolver section of this chapter for details.

An XSL Transformation Example

The Different ways to use the XslTransform object ( multi-xsl-transform.aspx ) example page is shown in Figure 11-23.

click to expand
Figure 11-23:

It loads the XML document and the stylesheet from disk at the start of the page, but then references the XML document in a range of ways to demonstrate the possibilities. It also performs a transformation to a String , and displays this in the page before writing it to disk separately “ rather than directly through the XslTransform object:

Notice that the XML string is not wrapped, and appears a single line in the page. However, if you open the hyperlink at the bottom of the example page (shown in Figure 11-24), you'll see the transformed result. Some of the nodes have been collapsed to reduce the overall size of the page in the screenshot:

click to expand
Figure 11-24:
Note

As with earlier examples, you must run this page in a browser on the web server itself to be able to open the transformed file using the physical path in the hyperlink at the bottom of the page.

Figure 11-25 shows the simple stylesheet being used. It extracts the <AuthorName> elements from the XML source document and generates a new XML document containing these “ within a root element named <AuthorList> :

click to expand
Figure 11-25:

The Code for the XslTransform Example

After creating the paths to the XML document and XSL stylesheet being used, the code in the page displays hyperlinks to these documents. Here, we're only interested in loading the documents and executing the transformation itself, and so haven't repeated the code.

We start by creating a new XslTransform object and loading the stylesheet into it, using the Load method with the path and filename of the stylesheet. To load the XML document in this example, an XmlTextReader is used. This isn't the quickest or shortest way to do it, but it aims to give you some ideas about how you can use the various objects in your projects.

For example, by loading the XML document with an XmlTextReader , you'd have the opportunity to validate it at the same time if this is a requirement. You would just need to assign an XmlValidatingReader to the XmlTextReader .

So, the code creates the XmlTextReader for the XML document and then creates a new XPathDocument from this XmlTextReader . The constructor for the XPathDocument automatically loads the XML from disk into the new XPathDocument . You can then create a new XPathNavigator based on the XPathDocument by calling the CreateNavigator method:

  'create a new XslTransform object to do the transformation   Dim objTransform As New XslTransform()     'load the XSL stylesheet into the XslTransform object   objTransform.Load(strXSLPath)     'create a new XmlTextReader object to fetch XML document   Dim objXTReader As New XmlTextReader(strXMLPath)     'create a new XPathDocument object from the XmlTextReader   Dim objXPDoc As New XPathDocument(objXTReader)     'create a new XPathNavigator object from the XPathDocument   Dim objXPNav As XPathNavigator   objXPNav = objXPDoc.CreateNavigator()  
Displaying the Transformed Result with an XmlReader

The Transform method of the XslTransform object can output the result of a transformation to an XmlReader object, a TextReader object, or an XmlWriter object. If you want the result to be available as a string, for use elsewhere in your applications, you can use an XmlReader or a TextReader object (depending on whether the result is XML that you want to parse as you use it, or some other format that can't be used with an XmlReader ).

Our example transforms the XML into an XmlReader object. We declare a variable to hold the object, and call the Transform method of the XslTransform object, passing it the XPathNavigator created for the XML document. The second argument allows us to pass in an XsltArgumentList object that can contain the parameters or arguments used by the stylesheet. As there are no parameters in our stylesheet, we use the value Nothing for this argument.

Once we get back the XmlReader object, we can display the contents “ the result of the transformation. The easiest way is to use the ReadOuterXml method of the reader:

  'create a variable to hold the XmlReader object that is   'returned from the Transform method   Dim objReader As XmlReader     'perform the transformation using the XSL file in the   'XslTransform and the XML document referenced by the   'XPathNavigator. The result is in the XmlReader object   objReader = objTransform.Transform(objXPNav, Nothing)     'display the contents of the XmlReader object   objReader.MoveToContent()   outResults.InnerText = objReader.ReadOuterXml()  
Writing the Transformed Result to Disk

The alternative output device for the Transform method of the XslTransform object is an XmlWriter object. This is ideal for piping the output back to a disk file.

In our example, we create an XmlTextWriter object (a public class that inherits from XmlWriter ), using a path and filename created earlier in the page. The second parameter to the constructor is the encoding to be used “ if we specify Nothing , it sets the encoding to the default UTF-8 .

Now we can use the XmlTextWriter to create the disk file. We start with an XML declaration (by simply calling the WriteStartDocument method) and add a comment element. We can then perform the transformation, sending the results directly to the XmlTextWriter “ which writes them straight to the disk file.

We finish by calling the WriteEndDocument method, to close any open elements and finalize the document, and then close it and display a hyperlink so that the results can be examined.

  'create an XmlTextWriter object to write result to disk   Dim objWriter As New XmlTextWriter(strOutPath, Nothing)     'write the opening <?xml .. ?> declaration and a comment   objWriter.WriteStartDocument()   objWriter.WriteComment("List of authors created " & Now())     'transform the XML into the XmlTextWriter   objTransform.Transform(objXPNav, Nothing, objWriter)     'ensure that all open elements are closed and end the document   objWriter.WriteEndDocument()     'flush the buffer to disk and close the file   objWriter.Close()   outFile.InnerHtml = "<a href=""" & strOutPath & """>" & strOutPath & "</a>"  

Loading Stylesheets and Schemas with an XmlResolver

One of the major changes to the System.Xml namespace in version 1.1 is a revision of the best practice and the various approaches available for loading an XSLT stylesheet into instances of the XslTransform class. These changes are associated with the percieved increasing risks from loading stylesheets that can contain script code, and references to other external resources. In version 1.0, once the stylesheet is loaded into the XslTransform object, it runs as fully trusted, irrespective of the source. To some extent, the same issue applies when loading a schema, though this is less likely to be a security risk than a stylesheet.

When you call the Load or Transform method of the XslTransform class, the Add method of the XmlSchemaCollection class, or the Compile method of the XmlSchema class, they automatically create an XmlUrlResolver instance for the schemas or stylesheets you reference, and use these to resolve any references to external entities, DTDs, other schemas, and resources pointed to by xsl:include and xsl:import statements.

However, where you are not able to verify whether a stylesheet or schema is safe “ for example, when loading it over the Web from an untrusted source “ you should instead create instances of the XmlUrlResolver or XmlSecureResolver classes that apply the security constraints you want to apply.

The XmlUrlResolver is the same as in verison 1.0 of the .NET Framework, but the XmlSecureResolver class is new in version 1.1. It is used for the same purposes as the XmlUrlResolver , but allows you to restrict the permissions available to the resources you use it to access.

Creating and Populating a CredentialCache

The XmlUrlResolver and XmlSecureResolver classes expose a Credentials property, which is a reference to a CredentialCache instance that can hold one or more credentials. Each credential is itself an instance of the NetworkCredential class. To create a NetworkCredential , you provide the user name or ID, the matching password, and ( optionally ) the domain in which that password should be validated in a call to the constructor:

  Dim objCred As New System.Net.NetworkCredential("  userid  ", "  password  ","  domain  ")  

The CredentialCache can be used to associate NetworkCredential instances with specific URLs so that the appropriate one is used when the stylesheet or schema is loaded.

To create a CredentialCache that contains more than one NetworkCredential , you create each one and add it to the cache, specifying the URL to which it applies in the Add method:

  ' create two NetworkCredential objects   Dim objCred1 As New System.Net.NetworkCredential("bob", "fH8$o3")   Dim objCred2 As New System.Net.NetworkCredential("alice", "TR3aq")     ' create and populate CredentialCache object   Dim objCC As New CredentialCache()   objCC.Add(New Uri("http://www.site1.com/"), "Basic", objCred1);   objCC.Add(New Uri("http://www.site2.com/"), "Basic", objCred1);   objCC.Add(New Uri("http://www.site3.com/"), "Digest", objCred2);  

Loading a Stylesheet with an XmlUrlResolver

Once you've created your NetworkCredential or CredentialCache , you can assign it to the Credentials property of a new XmlUrlResolver . You can then specify the XmlUrlResolver when calling the Load or Transform method of the XslTransform class, the Add method of the XmlSchemaCollection class, or the Compile method of the XmlSchema class “ for example, when you have a single NetworkCredential :

  Dim objResolver As New XmlUrlResolver()   objResolver.Credentials = objMyNetworkCredential   Dim objTransform As New XslTransform()   objTransform.Load(stylesheet-url, objResolver)  

Or when you have a CredentialsCache instance:

  Dim objResolver As New XmlUrlResolver()   objResolver.Credentials = objMyCredentialsCache   Dim objTransform As New XslTransform()   objTransform.Load(stylesheet-url, objResolver)  

As a result of this new approach, the recommended overloads of the Load method of the XslTransform class are now limited to these five (all others are obsolete). The first overload should only be used where you can verify the stylesheet is safe, or from a fully trusted source:

  • Load( stylesheet-url ) .

  • Load( stylesheet-url , XmlResolver ) .

  • Load( XPathNavigator , XmlResolver , Evidence ) .

  • Load( XmlReader , XmlResolver , Evidence ) .

  • Load( XPathNavigator , XmlResolver , Evidence ).

The Evidence parameter required for the last three overloads is a reference to an instance of the Evidence class. Microsoft's documentation covers four different scenarios, with different levels of security risk, when deciding how to manage the permissions that a stylesheet will have:

  • Where the stylesheet is self-contained, is located on a local disk, or comes from a source that you trust, and you want to allow it to execute with the same permissions as the code performing the transformation (the current assembly).

      objTransform.Load("stylesheet-url", objResolver, _   Me.GetType().Assembly.Evidence)  
  • Where the XSLT stylesheet comes from an outside source that is known, and is a verifiable URL, Evidence can be created from that URL using the CreateEvidenceForUrl method of the XmlSecureResolver object.

      Dim objEvidence As Evidence _   = XmlSecureResolver.CreateEvidenceForUrl("stylesheet-url")   objTransform.Load("stylesheet-url", objResolver, objEvidence)  
  • Where the XSLT stylesheet comes from an outside source that is not known or not trusted, and you want to ensure that script blocks are not processed , the XSLT document function is not supported, and privileged extension objects are disallowed , you can set the Evidence parameter to Nothing ( null in C#).

      objTransform.Load("  stylesheet-url  ", objResolver, Nothing)  
  • Where the XSLT stylesheet comes from an outside source that is not known or not trusted, and in addition to these limitaions, you want to ensure that xsl:import and xsl:include elements are not processed, you can set the XmlResolver parameter to Nothing ( null in C#).

      objTransform.Load("  stylesheet-url  ", Nothing)  

For the recommended overloads of the XslTransform.Transform method, see the .NET SDK topic Reference Class Library System.Xml.Xsl XslTransform Class Methods Transform Method.

For the recommended overloads of the XmlSchemaCollection.Add method, see the .NET SDK topic Reference Class Library System.Xml.Schema XslTransform Class Methods Transform Method.

For the recommended overloads of the XmlSchemaCollection.Compile method, see the .NET SDK topic eference Class Library System.Xml.Schema XmlSchemaCollection Class Methods Add Method.




Professional ASP. NET 1.1
Professional ASP.NET MVC 1.0 (Wrox Programmer to Programmer)
ISBN: 0470384611
EAN: 2147483647
Year: 2006
Pages: 243

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net