here's the xml document (containing a greece character):
<?xml version="1.0" encoding="UTF-16"?>
<?xml-stylesheet type="text/xsl" href="Untitled1.xslt"?>
<Text>this in a Λ </Text>
here's the xslt document:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="ISO-8859-1" />
<xsl:template match="/">
<html><head></head><body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="text">
</xsl:template>
</xsl:stylesheet>
now i use the TransformNode or TransformNodeToObject functions by MSXML to
get the html result. it works, but the result html document is always UTF-16
encoded, not ISO-8859-1.
What have I done wrong?
frank
>now i use the TransformNode or TransformNodeToObject functions by MSXML to
>get the html result. it works, but the result html document is always UTF-16
>encoded, not ISO-8859-1.
Which? TransformNode() or TransformNodeToObject()?
The reasons:-
* TransformNode() returns a BSTR (WideString) - which is UTF-16... therefore it
cannot be encoded as anything but UTF-16. This is why MSXML will ignore your
<xsl:output encoding="ISO-8859-1"/> when you use TransformNode().
* TransformNoToObject() - if the second parameter is a DOM then it will also be
UTF-16 because the DOM expects to be written to in UTF-16 encoding (similar to
the fact that in loadXML() takes a BSTR parameter) [not absolutely sure on this
one - as I never use this method!]
The solution(s):-
* Don't use TransformNode at all! :-)
* If you use TransformNodeToObject() make sure the second parameter is an object
that supports the IStream interface;
* or best use the IXSLTemplate and IXSLProcessor interfaces - and before running
the .transform() method of IXSLProcessor assign the .output property as an
object that supports the IStream interface. Then after a successful
.transform() you can read the stream (which will contain whatever encoding as a
proper stream). Note that the IXSLProcessor interface also has other
advantages - like being able to pass parameters to the stylesheet and set the
start mode.
Hope this helps
Marrow
http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
http://www.topxml.com/Xselerator
Frank von der Weth wrote in message <3c83574e_1@dnews>...
procedure TForm1.Button1Click(Sender: TObject);
VAR source : DOMDocument40;
target : DOMDocument40;
stylesheet : DOMDocument40;
sss : String;
Template : IXSLTemplate;
Processor : IXSLProcessor;
vIn, vOut : Variant;
SMem : TIMemoryStream;
wb : WORDBOOL;
begin
source:= CreateComObject(CLASS_DOMDocument) as DOMDocument;
target:= CreateComObject(CLASS_DOMDocument) as DOMDocument;
stylesheet:= CreateComObject(CLASS_FreeThreadedDOMDocument) as
DOMDocument;
source.load('untitled1.xml');
sss := source.parseError.Get_reason;
stylesheet.load ('untitled1.xslt');
sss := stylesheet.parseError.Get_reason;
Template := CreateComObject(CLASS_XSLTemplate) AS IXSLTemplate;
Template.Set_stylesheet(stylesheet);
Processor := Template.createProcessor;
Processor.setStartMode('', '');
TVarData(vIn).VType := vtVariant;
TVarData(vIn).VUnknown := Pointer(source);
Processor.Set_input(vIN);
SMem := TIMemoryStream.Create(TMemoryStream.Create);
TVarData(vOut).VType := vtVariant;
TVarData(vOut).VUnknown := SMem;
Processor.Set_output(vOut);
wb := Processor.transform;
SMem.MemoryStream.SaveToFile('output.txt');
SMem.Free;
end;
on the Set_output(vOut) i've got an access viloation. what's the problem?
frank
"Marrow" <marrow-NO-@-SPAM-marrowsoft.com> schrieb im Newsbeitrag
news:<3c835f47$1_2@dnews>...
"Marrow" <marrow-NO-@-SPAM-marrowsoft.com> schrieb im Newsbeitrag
news:3c835f47$1_2@dnews...
The following code works, try this...
unit Main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, ActiveX,
// from MSXML4 import!!...
MSXML2_TLB;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
InputXML: IXMLDOMDocument2;
InputXSL: IXMLDOMDocument2;
XSLTemplate: IXSLTemplate;
XSLProcessor: IXSLProcessor;
OutputStream: IStream;
Stat: TStatStg;
OutSize: Cardinal;
BytesRead: Cardinal;
OutputS: string;
OutputWS: WideString;
ByteOrderMarker: WideChar;
NewPos: Int64;
const
// UTF-16 BOM check...
BOM_UTF16LE = WideChar($FEFF);
begin
try
// create DOMs...
InputXML := CoDOMDocument40.Create;
InputXML.async := False;
InputXML.validateOnParse := False;
InputXML.setProperty('NewParser',True); // use MSXML4 fully!
InputXSL := CoFreeThreadedDOMDocument40.Create;
InputXSL.async := False;
InputXSL.validateOnParse := False;
InputXSL.setProperty('NewParser',True); // use MSXML4 fully!
// load XML and XSL...
if not InputXML.load('untitled1.xml') then
raise Exception.Create(InputXML.parseError.reason);
if not InputXSL.load('untitled1.xsl') then
raise Exception.Create(InputXML.parseError.reason);
// create the xsl template...
XSLTemplate := CoXSLTemplate40.Create;
XSLTemplate.stylesheet := InputXSL;
// create the xsl processor...
XSLProcessor := XSLTemplate.createProcessor;
// set the input for the processor...
XSLProcessor.input := InputXML;
// set start mode (if required)...
// XSLProcessor.setStartMode('mytestmode','');
// add any parameters (if required)...
// XSLProcessor.addParameter('mytestparam','hello','');
// create output stream...
CreateStreamOnHGlobal(0,True,OutputStream);
XSLProcessor.output := OutputStream;
// run the transformation...
if not XSLProcessor.transform then
raise Exception.Create('Unknown transformation failure');
// do whatever with the output stream...
// e.g. place it into a string...
OutputStream.Stat(Stat,0);
if (Stat.cbSize <> 0) then
begin
// check what type of string is in the stream (UTF-16 or other)...
OutputStream.Seek(0,STREAM_SEEK_SET,NewPos);
OutputStream.Read(@ByteOrderMarker,2,@BytesRead);
if ByteOrderMarker = BOM_UTF16LE then
begin
// utf-16 BOM detected - it is a widestring...
{$IFDEF STRIP_BOM}
// stript BOM from string...
SetLength(OutputWS,(Stat.cbSize - 2) div 2);
OutputStream.Read(@OutputWS[1],Stat.cbSize - 2,@BytesRead);
{$ELSE}
// include BOM in string...
OutputStream.Seek(0,STREAM_SEEK_SET,NewPos);
SetLength(OutputWS,Stat.cbSize div 2);
OutputStream.Read(@OutputWS[1],Stat.cbSize,@BytesRead);
{$ENDIF}
ShowMessage(OutputWS);
end
else
begin
// encoding may be utf-8 - but this is just a demo...
// (Note: MSXML3/4 does **not** use a UTF-8 BOM!)
SetLength(OutputS,Stat.cbSize);
OutputStream.Seek(0,STREAM_SEEK_SET,NewPos);
OutputStream.Read(@OutputS[1],Stat.cbSize,@BytesRead);
ShowMessage(OutputS);
end;
end;
except
on E: Exception do
MessageDlg(E.Message,mtError,[mbOK],0);
end;
end;
end.
Hope this helps
Marrow
http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
http://www.topxml.com/Xselerator
Frank von der Weth wrote in message <3c8372a3$1_2@dnews>...
To create the stream object replace
CreateStreamOnHGlobal(0,True,OutputStream);
with
ATStreamClass := TMemoryStream.Create; //or any other TStream descendent
Adapt := TStreamAdapter.Create(ATStreamClass);
Adapt.Seek(0, 0, tPos);
OutputStream := Adapt as IStream;
Then use the ATStream to acces the stream.
Surjit.
"Marrow" <marrow-NO-@-SPAM-marrowsoft.com> wrote in message
news:3c839fe5_1@dnews...
thank's a lot for the great tips, all works fine!!
regards
frank
"Surjit Rajput" <Surjit...@hotmail.com> schrieb im Newsbeitrag
news:3c83eea1_2@dnews...