program xidelcgi; {$mode objfpc}{$H+} uses xidelbase, simplehtmltreeparser, rcmdlinecgi, {utf8tools, }sysutils, strutils, math, bbutils, extendedhtmlparser, xquery.internals.common, xidelcrt { you can add units after this }; const ExampleHTML: string = ''#13#10+ ''#13#10+ ''#13#10+ '
Hello
'#13#10+ ''#13#10+ ''#13#10+ ''#13#10+ ''#13#10+ ''#13#10+ '
123other
foocolumns
barare
xyzignored
'#13#10+ ''; ExampleTemplate:string = ''#13#10+ ''#13#10+ ''#13#10+ ''#13#10+ '
{col:=text()}
'; ExampleCSS: string = '#t2 tr td:first-child'; ExampleXPath: string = 'id("t2") / tbody / tr / td[1]'; ExampleXQuery1: string = 'xquery version "1.0";'#13#10'declare function local:test($table as element()){'#13#10 + ' $table / tbody / tr / td[1]'#13#10'};'#13#10+ 'local:test(id("t2"))'; ExampleXQuery3_0: string = 'xquery version "3.0";'#13#10'declare function local:test($table as element()){'#13#10 + ' $table / tbody / tr / td[1]'#13#10'};'#13#10+ 'local:test(id("t2"))'; ExampleXQuery3_1: string = 'xquery version "3.1";'#13#10'declare function local:test($table as element()){'#13#10 + ' $table / tbody / tr / td[1]'#13#10'};'#13#10+ 'local:test(id("t2"))'; ExampleTemplateResult: string = 'col: 123'#13#10 + 'col: foo'#13#10 + 'col: bar'#13#10 + 'col: xyz'; ExampleOtherResult: string = '123'#13#10 + 'foo'#13#10 + 'bar'#13#10 + 'xyz'; var wasRaw: Boolean = false; permalink, rawpermalink: String; procedure w(const s: string); begin xidelcrt.wln(s); end; function extractKindToString(kind: TExtractionKind): string; begin case kind of ekAuto: exit('auto'); ekXPath2: exit('xpath2'); ekXPath3_0: exit('xpath3'); ekXPath3_1: exit('xpath3_1'); ekPatternHTML: exit('html-pattern'); ekPatternXML: exit('xml-pattern'); ekCSS: exit('css'); ekXQuery1: exit('xquery1'); ekXQuery3_0: exit('xquery3'); ekXQuery3_1: exit('xquery3_1'); else exit('auto'); end; end; var oldinoutfunc, oldflushfunc: CodePointer; Procedure HTMLEscapedFileWriteFunc(var t:TextRec); type FileFunc = Procedure(var t : TextRec); procedure writeEscaped; var helper: TXHTMLStrBuilder; buffer: string; bufferptr, bufferend: PChar; size: integer; begin helper.init(@buffer, 2*t.bufpos); helper.appendHTMLText(@t.bufptr^[0], t.bufpos); helper.final; bufferptr := pchar(buffer); bufferend := bufferptr + length(buffer); while bufferptr < bufferend do begin size := min(t.bufsize, bufferend - bufferptr); move(bufferptr^, t.bufptr^, size); t.bufpos := size; FileFunc(oldinoutfunc)(t); bufferptr += size; end; end; var needescape: Boolean; i: Integer; begin needescape := false; for i := 0 to t.bufpos - 1 do begin needescape := t.bufptr^[i] in ['<','>','&']; if needescape then break; end; //writeln(stderr, needescape, ' ', t.bufpos); if not needescape then FileFunc(oldinoutfunc)(t) else writeEscaped; end; type { TCommandLineReaderBreaker } TCommandLineReaderBreaker = class(TCommandLineReaderCGI) procedure setString(const n,v: string); procedure setFlag(const n: string; v: boolean); end; var firstExtractionKind: string; procedure printPre(extractionKind: TExtractionKind); function example(t: string): string; begin if (t = mycmdline.readString('extract-kind')) and (mycmdline.readString('extract') <> '') then exit(mycmdline.readString('extract')); case t of 'xpath', 'xpath2', 'xpath3', 'xpath3.0', 'xpath3.1': exit(ExampleXPath); 'xquery1': exit(ExampleXQuery1); 'xquery', 'xquery3', 'xquery3.0': exit(ExampleXQuery3_0); 'xquery3.1': exit(ExampleXQuery3_1); 'css': exit(ExampleCSS); {'template', 'auto':} else exit(ExampleTemplate); end; end; function kind(t, n: string): string; begin result := ''], ['\\', '\n', '\''', '&', '"', '<', '>'], [rfReplaceAll]) + '''); update();"'; result += '/> '+ n; end; function checkbox(t, n: string): string; begin result := ' '' then n += ': '; result := n + ' '; end; begin outputHeader := ''; setOutputFileName('stdout:///', mycmdline); if (mycmdline.readFlag('case-sensitive')) then xqueryDefaultCollation:='http://www.w3.org/2005/xpath-functions/collation/codepoint'; if mycmdline.readFlag('raw') then begin case mycmdLine.readString('output-format') of //'xml', 'xml-wrapped': w('Content-Type: application/xml'); //'html': w('Content-Type: text/html'); 'json', 'json-wrapped': w('Content-Type: application/json'); {'adhoc':} else w('Content-Type: text/plain'); end; w('Xidel-Detected-Extraction-Kind: '+extractKindToString(extractionKind)); w(''); wasRaw := true; exit; end; if mycmdline.readString('extract-kind') <> 'auto' then firstExtractionKind := mycmdline.readString('extract-kind') else if mycmdline.readString('extract') <> '' then firstExtractionKind := extractKindToString(extractionKind) else firstExtractionKind:=''; w('Content-Type: text/html'); w(''); w(''); w('Template / XPath 3.0 / XQuery 3.0 / CSS 3 Selector / JSONiq Online Tester'); w(''); w(''); w(''); w(''); w(' '); w(''); w(''); w(''); w('

Template / XPath 3.0 / XQuery 3.0 / CSS 3 Selector / JSONiq Online Tester

'); w('(You can find the documentation below)

'); w('
'); w('
'+select('input-format', 'HTML/XML-Input file', ['auto', 'html', 'xml', 'xml-strict']) + '
'); w('
'+kind('template', 'Template')+kind('xpath3.0', 'XPath 3.0')+ kind('xpath2', '2.0')+kind('xquery3.0', 'XQuery 3.0')+kind('xquery1', '1')+kind('css', 'CSS 3.0 selectors')+kind('auto', 'Autodetect')); w('
'); w('

'+checkbox('no-auto-update', 'disable auto refresh')+' ' {id="codemirrorspan"} + checkbox('no-highlighting', 'disable syntax highlighting') +''); w('
Output Options: '); w( select('printed-node-format', 'Node format:', ['text', 'xml', 'html']) + select('output-format', 'Output format:', ['adhoc', 'html', 'xml', 'xml-wrapped', 'json-wrapped', 'bash', 'cmd'])); w(checkbox('print-type-annotations', 'Show types') + checkbox('hide-variable-names', 'Hide variable names') ); w('
Compatibility: '+select('compatibility', '', ['Standard XQuery', 'Standard XQuery+JSONiq', 'Enable all extensions', 'Custom']) + ''+ checkbox('no-extended-strings', 'Disable extended strings (e.g. x"{$varname}") ') + checkbox('no-json', 'Disable JSONiq (e.g. {"a": 1}("a"))') + checkbox('no-json-literals', 'Disable JSONiq literals (true,false,null)') + checkbox('only-json-objects', 'Only JSON types in objects (e.g. {"a": null} != {"a": ()})') + select('dot-notation', '    Allow dot notation (e.g. {"a": 1}.a): ', ['off', 'unambiguous', 'on']) + checkbox('strict-type-checking', 'Strict type checking') + checkbox('strict-namespaces', 'Strict namespaces') + checkbox('case-sensitive', 'case sensitive')); w(''); w('
'); w('
Work in progress: ' + kind('xpath3.1', 'XPath 3.1') + kind('xquery3.1', 'XQuery 3.1')+'
'); w('
'); { w(''); w(''); w(''); w(''); w('');} w(''); w(''); w(''); w(''); w('
'); w('Result of the above expression applied to the above HTML file:
'); w('
'); w(', '); w('result-only'); //w(''); w('



'); //w(cgi.QueryString); w('

What is this about?

'); w('Here you can test HTML templates, CSS 3 selectors, standard XPath 2.0 / 3.0 / XQuery 1.0 / 3.0 and JSONiq expressions.
'); w('It is an example for my Pascal Internet Tools library written for VideLibri and implementing these queries.
'); //w('The template example shows the two most basic template commands (read/loop) and copies the first column of a table.'+' .
'); w('
You can find more details in the corresponding unit documentation:
'); w(link('http://benibela.de/documentation/internettools/xquery.TXQueryEngine.html', 'Documentation of the XQuery / XPath / CSS 3 selector implementation')); w(link('http://benibela.de/documentation/internettools/extendedhtmlparser.THtmlTemplateParser.html', 'Documentation of the template syntax')); w('
Other related links:
'); w(link('http://www.benibela.de/sources_en.html#internettools', 'Internet Tools library', ', the library page')); w(link('http://www.benibela.de/documentation/internettools/xqts.html', 'XQuery Test Suite Results')); w(link('http://www.videlibri.de/xidel.html', 'Xidel command line tool', ', a litte tool using this library for web page downloading / scraping')); w(link('https://sourceforge.net/p/videlibri/code/ci/tip/tree/', 'Source repository', '', ' rel="nofollow"')); w(link('https://github.com/benibela/xidel', 'Github mirror (Xidel excluding library)', '', ' rel="nofollow"')); w(link('https://bitbucket.org/benibela/xidel', 'Bitbucket mirror (Xidel excluding library)', '', ' rel="nofollow"')); w(''); w(''); {sl := tstringlist.create; cgi.AddResponseLn('reqvar:'); cgi.GetRequestVarList(sl); for i:=0 to sl.Count-1 do cgi.AddResponseLn(sl[i]+'
'); cgi.AddResponseLn('cgivar:'); cgi.GetCGIVarList(sl); for i:=0 to sl.Count-1 do cgi.AddResponseLn(sl[i]+'
'); sl.free;} w(''); end; { TCommandLineReaderBreaker } procedure onPostParseCmdLine; var onn: String; off: String; change: string; temp: TStringArray; i: Integer; begin i := 1; case lowercase(mycmdline.readString('compatibility')) of 'standard xquery': i := 1; 'standard xquery+jsoniq': i := 2; 'enable all extensions': i := 3; else exit; //'Custom' end; onn := compatibiltiyOptionsOn[i]; off := compatibiltiyOptionsOff[i]; change := compatibiltiyOptionsChange[i]; temp := strSplit(onn, ';', false); for i := 0 to high(temp) do TCommandLineReaderBreaker(mycmdline).setFlag(temp[i],true); temp := strSplit(off, ';', false); for i := 0 to high(temp) do TCommandLineReaderBreaker(mycmdline).setFlag(temp[i],false); temp := strSplit(change, ';', false); for i := 0 to high(temp) do TCommandLineReaderBreaker(mycmdline).setString(strSplit(temp[i], '=')[0],strSplit(temp[i], '=')[1]); end; procedure TCommandLineReaderBreaker.setString(const n, v: string); begin findProperty(n)^.strvalue:=v; end; procedure TCommandLineReaderBreaker.setFlag(const n: string; v: boolean); begin findProperty(n)^.flagvalue:=v; end; begin xidelbase.cgimode := true; xidelbase.allowInternetAccess := false; xidelcrt.allowFileAccess := false; xidelbase.mycmdline := TCommandLineReaderCGI.create; mycmdline.beginDeclarationCategory('CGI Only options'); mycmdline.declareFlag('raw', 'Only prints the output of the expression'); mycmdline.declareFlag('no-auto-update', 'No automatical javascript based autoupdate'); mycmdline.declareFlag('no-highlighting', 'No syntax highlighting'); mycmdline.declareFlag('case-sensitive', 'Case sensitive'); mycmdline.declareString('compatibility', 'XQuery compatibility options', 'Enable all extensions'); xidelbase.onPostParseCmdLine := @onPostParseCmdLine; xidelbase.onPreOutput := @printPre; xidelbase.perform; if not wasRaw then printPost; end.