mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 16:35:33 +00:00
The DTD reference at tavultesoft.com is no longer valid. In order for the .xml file to be parseable, we need to remove the DTD reference. This resolves the issue where the emitted .html file is blank, and adds an additional step of verifying that the .xml file loads successfully in the XML to HTML transform.
263 lines
7.6 KiB
ObjectPascal
263 lines
7.6 KiB
ObjectPascal
(*
|
|
Name: VisualKeyboardExportHTML
|
|
Copyright: Copyright (C) SIL International.
|
|
Documentation:
|
|
Description:
|
|
Create Date: 20 Jun 2006
|
|
|
|
Modified Date: 8 Jun 2012
|
|
Authors: mcdurdin
|
|
Related Files:
|
|
Dependencies:
|
|
|
|
Bugs:
|
|
Todo:
|
|
Notes:
|
|
History: 20 Jun 2006 - mcdurdin - Initial version
|
|
23 Aug 2006 - mcdurdin - Initial refactor for new visual keyboard
|
|
04 Dec 2006 - mcdurdin - Support new XML+XSLT OSK export
|
|
22 Jan 2007 - mcdurdin - Fix XSLT not loading for loading include files
|
|
19 Nov 2007 - mcdurdin - I1157 - const string parameters
|
|
29 Sep 2008 - mcdurdin - I1658 - Add support for export graphics options
|
|
16 Jan 2009 - mcdurdin - Widestring filenames
|
|
04 Jun 2009 - mcdurdin - I2003 - UTF8Encode replacement
|
|
03 May 2011 - mcdurdin - I2890 - Record diagnostic data when encountering registry errors
|
|
18 May 2012 - mcdurdin - I3306 - V9.0 - Remove TntControls + Win9x support
|
|
08 Jun 2012 - mcdurdin - I3337 - V9.0 - Review of input/output for Unicode
|
|
*)
|
|
unit VisualKeyboardExportHTML; // I3306
|
|
|
|
interface
|
|
|
|
uses
|
|
System.UITypes,
|
|
Windows, VisualKeyboard, Classes, SysUtils, Graphics, VisualKeyboardParameters;
|
|
|
|
type
|
|
TVisualKeyboardExportHTML = class(TVisualKeyboardExport)
|
|
private
|
|
FFolders, FGraphical: Boolean;
|
|
public
|
|
constructor Create(AKbd: TVisualKeyboard; AFolders: Boolean = True; AGraphical: Boolean = True); reintroduce;
|
|
procedure ExportToFile(FileName: WideString); override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
ActiveX,
|
|
ComObj,
|
|
Controls,
|
|
DebugPaths,
|
|
Dialogs,
|
|
ErrorControlledRegistry,
|
|
KeymanPaths,
|
|
RegistryKeys,
|
|
Unicode,
|
|
utildir,
|
|
VersionInfo,
|
|
VisualKeyboardExportXML,
|
|
MSXML2_TLB,
|
|
xmldoc,
|
|
xmlintf;
|
|
|
|
{ TVisualKeyboardExportHTML }
|
|
|
|
function GetOSKXSLPath: string;
|
|
var
|
|
keyman_root: string;
|
|
begin
|
|
Result := ExtractFilePath(ParamStr(0)) + 'xml\osk\';
|
|
if not DirectoryExists(Result) then
|
|
begin
|
|
if TKeymanPaths.RunningFromSource(keyman_root) then
|
|
begin
|
|
Result := keyman_root + 'windows\src\engine\xml\osk\';
|
|
end
|
|
else
|
|
begin
|
|
with TRegistryErrorControlled.Create do // I2890
|
|
try
|
|
RootKey := HKEY_LOCAL_MACHINE;
|
|
if OpenKeyReadOnly(SRegKey_KeymanEngine_LM) and ValueExists(SRegValue_RootPath) then
|
|
Result := IncludeTrailingPathDelimiter(ReadString(SRegValue_RootPath)) + 'xml\osk\';
|
|
finally
|
|
Free;
|
|
end;
|
|
|
|
if not DirectoryExists(Result) then
|
|
Result := '';
|
|
end;
|
|
end;
|
|
Result := GetDebugPath('Debug_OSKXSLPath', Result, True);
|
|
end;
|
|
|
|
const
|
|
{ GUID's from MSXML2_TLB.pas }
|
|
//CLASS_DOMDocument26: TGUID = '{F5078F1B-C551-11D3-89B9-0000F81FE221}';
|
|
CLASS_DOMDocument30: TGUID = '{F5078F32-C551-11D3-89B9-0000F81FE221}';
|
|
CLASS_DOMDocument40: TGUID = '{88D969C0-F192-11D4-A65F-0040963251E5}';
|
|
|
|
function TryObjectCreate(const GuidList: array of TGuid): IUnknown;
|
|
var
|
|
I: Integer;
|
|
Status: HResult;
|
|
begin
|
|
Status := S_OK;
|
|
for I := Low(GuidList) to High(GuidList) do
|
|
begin
|
|
Status := CoCreateInstance(GuidList[I], nil, CLSCTX_INPROC_SERVER or
|
|
CLSCTX_LOCAL_SERVER, IDispatch, Result);
|
|
if Status = S_OK then Exit;
|
|
end;
|
|
OleCheck(Status);
|
|
end;
|
|
|
|
function CreateDOMDocument: IXMLDOMDocument2;
|
|
begin
|
|
Result := TryObjectCreate([CLASS_DOMDocument40, CLASS_DOMDocument30]) as IXMLDOMDocument2;
|
|
if not Assigned(Result) then
|
|
raise Exception.Create('MS XML DOM 3.0 not installed');
|
|
end;
|
|
|
|
constructor TVisualKeyboardExportHTML.Create(AKbd: TVisualKeyboard; AFolders,
|
|
AGraphical: Boolean);
|
|
begin
|
|
inherited Create(AKbd);
|
|
FFolders := AFolders;
|
|
FGraphical := AGraphical;
|
|
end;
|
|
|
|
procedure TVisualKeyboardExportHTML.ExportToFile(FileName: WideString);
|
|
var
|
|
doc: IXMLDomDocument2;
|
|
xsldoc: IXMLDOMDocument2;
|
|
xslproc: IXSLProcessor;
|
|
xslt: IXSLTemplate;
|
|
nodes: IXMLDOMNodeList;
|
|
FOutput: WideString;
|
|
//ss: TStringStream;
|
|
f: TSearchRec;
|
|
s: string;
|
|
files: TStringList;
|
|
FSubdir: WideString;
|
|
stemp: WideString;
|
|
i: Integer;
|
|
begin
|
|
{ Structure for HTML keyboard: file + subdirectory with images; always output as UTF-8? }
|
|
|
|
stemp := ChangeFileExt(FileName, '') + '.xml';
|
|
try
|
|
|
|
with TVisualKeyboardExportXML.Create(FKbd) do
|
|
try
|
|
ExportToFile(stemp);
|
|
finally
|
|
Free;
|
|
end;
|
|
|
|
files := TStringList.Create;
|
|
try
|
|
doc := CreateDOMDocument;
|
|
try
|
|
doc.async := False;
|
|
doc.validateOnParse := False;
|
|
if not doc.load(stemp) then
|
|
begin
|
|
if doc.parseError <> nil then
|
|
begin
|
|
ShowMessage('Could not load XML: '+doc.parseError.reason);
|
|
Exit;
|
|
end;
|
|
end;
|
|
xsldoc := ComsFreeThreadedDOMDocument.Create;
|
|
try
|
|
xsldoc.async := False;
|
|
xsldoc.resolveExternals := True;
|
|
xsldoc.validateOnParse := False;
|
|
if not xsldoc.load(GetOSKXSLPath + 'osk.xsl') then
|
|
begin
|
|
if xsldoc.parseError <> nil then
|
|
begin
|
|
ShowMessage('Could not load transform '+GetOSKXSLPath + 'osk.xsl: '+xsldoc.parseError.reason);
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
xsldoc.setProperty('SelectionNamespaces', 'xmlns:oskexportdetails=''http://www.tavultesoft.com/xml/oskexportdetails''');
|
|
xsldoc.setProperty('SelectionLanguage', 'XPath');
|
|
|
|
nodes := xsldoc.documentElement.selectNodes('//oskexportdetails:includefile');
|
|
for i := 0 to nodes.length - 1 do
|
|
files.Add(nodes.item[i].text);
|
|
|
|
xslt := ComsXSLTemplate.Create;
|
|
xslt.stylesheet := xsldoc;
|
|
|
|
xslproc := xslt.createProcessor;
|
|
|
|
xslproc.input := doc;
|
|
xslproc.addParameter('graphical', FGraphical, '');
|
|
xslproc.addParameter('folders', FFolders, '');
|
|
|
|
xslproc.transform;
|
|
FOutput := xslproc.output; // doc.transformNode(xsldoc);
|
|
finally
|
|
xsldoc := nil;
|
|
end;
|
|
finally
|
|
doc := nil;
|
|
end;
|
|
|
|
with TStringList.Create do
|
|
try
|
|
Text := FOutput;
|
|
SaveToFile(FileName, TEncoding.UTF8); // I3337
|
|
finally
|
|
Free;
|
|
end;
|
|
|
|
if FFolders then
|
|
begin
|
|
FSubdir := ChangeFileExt(FileName, '')+'_files';
|
|
|
|
if DirectoryExists(FSubdir) and not DirectoryEmpty(FSubdir) then
|
|
begin
|
|
if MessageDlg('The subdirectory "'+FSubdir+'" already exists. Images for the HTML file will be placed in this '+
|
|
'subdirectory. If you continue, any files currently in the directory will be deleted.'#13#10#13#10+
|
|
'Continue exporting and delete all existing files in the subdirectory?', mtConfirmation, mbOkCancel, 0) = mrCancel then Exit;
|
|
if not EmptyDirectory(FSubdir) then
|
|
if MessageDlg('The subdirectory "'+FSubdir+'" was not able to be emptied. Continue exporting anyway?',
|
|
mtConfirmation, mbOkCancel, 0) = mrCancel then Exit;
|
|
end;
|
|
|
|
CreateDir(FSubdir);
|
|
end
|
|
else
|
|
FSubdir := ExtractFileDir(FileName);
|
|
|
|
s := GetOSKXSLPath;
|
|
if FGraphical then
|
|
for i := 0 to files.Count - 1 do
|
|
CopyFile(PChar(s+files[i]), PChar(FSubDir+'\'+files[i]), True);
|
|
finally
|
|
files.Free;
|
|
end;
|
|
|
|
s := ChangeFileExt(stemp, '')+'_xml_files\';
|
|
if FGraphical then
|
|
if FindFirst(s + '*', 0, f) = 0 then
|
|
begin
|
|
repeat
|
|
CopyFile(PChar(s+f.Name), PChar(FSubDir+'\'+f.Name), True);
|
|
until FindNext(f) <> 0;
|
|
FindClose(f);
|
|
end;
|
|
RecursiveDelete(ExcludeTrailingPathDelimiter(s));
|
|
|
|
finally
|
|
DeleteFile(stemp);
|
|
end;
|
|
end;
|
|
|
|
end.
|