问题
I am trying to perform an XSLT transformation with Delphi XE8 and am running into problems. My XSL file refers to an external XSL file using an import statement whose href attribute has a relative path. The transform fails with the error "Named template 'skrivUtDate' does not appear in the stylesheet." The definition 'skrivUtDate' is located in the external XSL file. The definition looks like the following:
<xsl:template name="skrivUtDate">
<xsl:param name="oppgittTid"/>
<xsl:if test="string-length($oppgittTid)!=0">
<xsl:value-of select="substring($oppgittTid,9,2)"/>.<xsl:value-of select="substring($oppgittTid,6,2)"/>.<xsl:value-of select="substring($oppgittTid,3,2)"/>
</xsl:if>
</xsl:template>
I have placed the external XSL file in the appropriate directory (relative to the original XSL file) but I get the same error (I have also tried all other conceivable directories for this external file, but none have worked). However, I can perform the transformation using EditX XML Editor, so I do not think that the XSL is invalid (Note that this XSL file was provided by a third party, and apparently it is being used successfully by some folks using development platforms other than Delphi).
Here is the opening segment of the XSL file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:ref="http://www.kith.no/xmlstds/henvisning/2012-02-15"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:po="http://www.kith.no/xmlstds/po/poKomponent/2009-06-30"
xmlns:fk1="http://www.kith.no/xmlstds/felleskomponent1"
exclude-result-prefixes="ref xhtml po fk1">
<xsl:import href="../../Felleskomponenter/funksjoner.xsl"/>
And, yes, the funksjoner.xsl file is in a directory named Felleskomponenter.
My very simple test uses something similar to the following pseudo code:
var
XML : IXMLDocument;
XSL : IXMLDocument;
s: WideString;
begin
XML := TXMLDocument.Create(self);
XML.FileName := 'C:\somepath\some.xml';
XML.Active := True;
XSL := TXMLDocument.Create(Self);
XSL.FileName := 'C:\someotherpath\somefile.xsl';
XSL.Active := True;
XML.DocumentElement.TransformNode(XSL.DocumentElement, s);
I know that Delphi XE7 started shipping with the Omni XML DOM as well as the ADOM, but those are apparently absent from Delphi XE8. I was hoping that using a different document object model might address the problem.
The XML is pretty complicated, as is the XSL.
Does any body have any suggestions for alternative ways to perform XSLT transformations with Delphi XE8?
回答1:
For XSLT to work properly in Delphi, you need to use MSXML to load the XML and XSL files. This post gives an example on how to use MSXML with Delphi. The TransformNode
uses MSXML under the hood.
Something along the following should work (taken from here, incomplete snippet):
var
xmlEmployees, xslStyle : IXMLDOMDocument;
begin
xmlEmployees := CoDOMDocument.Create;
xslStyle := CoDOMDocument.Create;
xmlEmployees.load('employees.xml');
xslStyle.load('empuksna.xsl');
result := xmlEmployees.transformNode(xslStyle);
end;
Likewise, if you were to load your XML and XSL through a string, the original location gets lost. Most processors support setting the base uri, but it looks like IXSLProcessor does not have such option.
You also ask for an alternative. DIXML support libxslt which is in quite some respects superior to MSXML (though not to .NET's XSLT, which is another alternative, if you like interop'ing with .NET). The package of DIXML comes with a bunch of demo's and examples in the demo folder.
If you can switch to .NET, this (rather old) DrDobb's article shows how to do XSLT with .NET and Delphi and also shows yet another alternative for a transformation (though it assumed Delphi 7, not sure it still applies).
来源:https://stackoverflow.com/questions/32697647/alternatives-for-xslt-transformations-with-delphi-xe8