|
|||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionXML and XSLT have done much in the way to ease processing chunks of data. No longer must we write custom parsers for each 'fixed field' layout we encounter which can become a maintenance nightmare. With XSLT, we can transform XML into another shape, for presentation or for another consumer process. When standard XSLT functionality is not enough, we can extend its reach by adding our own custom components. The type of functionality that can be introduced is not limited but one must be diligent in its use. In my opinion, it would be unwise to drive business logic from a stylesheet. There are other scenarios, however, where this may be practical: data that needs to be translated against a database or a complex calculation that exceeds the limitations of the built-in math functionality. The Sample CodeThe sample is made up of a WTL test client, an XSLT Transform component and an extension function component to do the database lookup. I have included a subset of the Bibliography Access database as a data source, a stylesheet and a few input files. The Extension FunctionThe extension function is a regular COM component that must support
The sample extension function exposes 3 public methods and 1 property. Each has differing parameter lists to show some of the nuances when making calls outside of the XSLT Processor. interface IBibTitles : IDispatch{
[id(1), helpstring("method GetBookTitle")]
HRESULT GetBookTitle([in] BSTR isbn, [out,retval] BSTR* bookTitle);
[id(2), helpstring("method GetYearPublished")]
HRESULT GetYearPublished([in] BSTR isbn, [out,retval] LONG* yearPublished);
[id(3), helpstring("method GetIsbnByYear")]
HRESULT GetIsbnByYear([in] LONG year, [out,retval] BSTR* result);
[propget, id(4), helpstring("property ProcessTime")]
HRESULT ProcessTime([out, retval] BSTR* pVal);
};
Each method queries the database and the return value is written directly to the XML output stream. If the query does not return any rows, the returned value is Other than that, there's nothing special about this component. It can be written in any language that supports COM: VC++, Visual Basic or any .NET language. If you use a .NET language, you will need to register the assembly's type library (Regasm.exe). The XSLTransform ComponentIn order to get an XSLT Processor, load the stylesheet into a I create the Free Threaded Document, // get a processor
MSXML2::IXSLProcessorPtr pProc;
pProc = pTemplate->createProcessor();
pProc->addObject(pExtFunc, _T("http://myuniquenamespace/titles"));
pProc->input = pDom.GetInterfacePtr();
pProc->transform();
Notice the call to The StylesheetIn the stylesheet, we must declare the object namespace in the <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:db="http://myuniquenamespace/titles">
Call the extension function in the <xsl:value-of select="db:GetBookTitle(ROOT/BK)"/>
This is due to the fact that an XPath expression evaluates to an XML tree fragment. Our extension component doesn't know anything about XML, just strings and numbers. We can fix this by using the <xsl:value-of select="db:GetBookTitle(string(ROOT/BK))"/>
If the XPath expression evaluates to a node that has children, the string value will be a space-delimited string of all text under that node. XML data
<ROOT>
<BK>0-0230081-2-1</BK>
<BK>0-0230948-1-8</BK>
<BK>0-0301413-4-6</BK>
</ROOT>
XPath:
<xsl:value-of select="string(ROOT)"/>
Evaluates to:
0-0230081-2-1 0-0230948-1-8 0-0301413-4-6
Keep this in mind when you're debugging. If your function exposes properties, they can be referenced using <xsl:value-of select="db:get-ProcessTime()"/>
SummaryThat about does it. The only thing left is the test client but there's nothing special happening there. Using the An XSLT Processor extension function is a regular COM component that supports Included with the sample code are 3 input files. The first, input1.xml, has a few ISBN numbers that are present in the database. Input2.xml has 1 ISBN number that is not in the database and a tag that will cause the stylesheet to call With .NET on the move, MSXML4 may already be outdated. Whether or not that is the case, I think it's a good idea to know what's going on behind the scenes. Although I don't believe that extending the processor will always be the best overall choice, it's nice to have when you need it. Points of InterestWhile I have not spent lots of time exploring the full XML feature set provided by .NET, I'm sure that it has improvements over MSXML 4. I've spent a number of hours trying to pass an XML fragment into the extension function with no success.
|
||||||||||||||||||||||||||||||||||||||||||||||||