#############################################################################
##
#W BibXMLextTools.gi GAPDoc Frank Lübeck
##
##
#Y Copyright (C) 2006, Frank Lübeck, Lehrstuhl D für Mathematik,
#Y RWTH Aachen
##
## The files BibXMLextTools.g{d,i} contain utility functions for dealing
## with bibliography data in the BibXMLext format. The corresponding DTD
## is in ../bibxmlext.dtd.
##
###########################################################################
##
## templates to fill for new entries, this describes the possible entries
## and their structure
## (This is generated from Bibxmlext from bibxmlextinfo.g, which is created
## automatically with the adhoc utility parsedtd.g.)
BindGlobal("BibXMLextStructure", rec());
BibXMLextStructure.fill := function()
local l, els, i, type;
for type in Filtered(Bibxmlext[1].entry, a-> a <> "or") do
l := Bibxmlext[1].(type);
els := [];
i := 1;
while i <= Length(l) do
if i = Length(l) or not l[i+1] in ["optional", "repeated"] then
Add(els, [l[i], true]);
i := i+1;
else
Add(els, [l[i], false]);
i := i+2;
fi;
od;
# Print(type,": ",Filtered(els, a->not IsString(a[1])),"\n");
BibXMLextStructure.(type) := els;
od;
Unbind(BibXMLextStructure.fill);
end;
BibXMLextStructure.fill();
MakeImmutable(BibXMLextStructure);
## <#GAPDoc Label="TemplateBibXML">
##
##
## list of types or string
##
## Without an argument this function returns a list of the supported entry
## types in BibXMLext documents.
##
## With an argument type of one of the supported types the function
## returns a string which is a template for a corresponding BibXMLext entry.
## Optional field elements have a * appended. If an element has
## the word OR appended, then either this element or the next must/can
## be given, not both. If AND/OR is appended then this and/or the next
## can/must be given. Elements which can appear several times have a
## + appended. Places to fill are marked by an X .
##
## TemplateBibXML();
## [ "article", "book", "booklet", "conference", "inbook",
## "incollection", "inproceedings", "manual", "mastersthesis", "misc",
## "phdthesis", "proceedings", "techreport", "unpublished" ]
## gap> Print(TemplateBibXML("inbook"));
##
##
## X X +
## OR
##
## X X +
##
## X
## X AND/OR
## X
## X
## X
## X *OR
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *OR
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *
## X *+
##
## ]]>
##
##
## <#/GAPDoc>
# args: [type] with no argument prints the possible types
InstallGlobalFunction(TemplateBibXML, function(arg)
local type, res, add, a, b;
if Length(arg) = 0 then
return Filtered(RecNames(BibXMLextStructure), a-> not a in ["fill"]);
fi;
type := arg[1];
if type = "fill" or not IsBound(BibXMLextStructure.(type)) then
Error("There are no bib-entries of type ", type,".\n");
fi;
res := "<";
Append(res, type);
Append(res, ">\n");
add := function(a)
if a[1] in [ "author", "editor" ] then
Append(res, " <");
Append(res, a[1]);
Append(res, ">\n X X +\n ");
Append(res, a[1]);
Append(res, ">");
elif a[1] = "other" then
Append(res, " X ");
else
Append(res, " <");
Append(res, a[1]);
Append(res, ">X");
Append(res, a[1]);
Append(res, ">");
fi;
if not a[2] then
Add(res, '*');
fi;
if a[1] = "other" then
Add(res, '+');
fi;
Append(res, "\n");
if not IsString(res) then Error("nanu");fi;
end;
for a in BibXMLextStructure.(type) do
if IsString(a[1]) then
add(a);
elif Length(a[1]) = 3 and a[1][2] = "or" then
if IsString(a[1][1]) then
add([a[1][1], a[2]]);
Unbind(res[Length(res)]);
Append(res,"OR\n");
elif a[1][1] = [ "chapter", "pages", "optional" ] then
add([a[1][1][1], a[2]]);
Unbind(res[Length(res)]);
Append(res,"AND/OR\n");
else
Error("unknown case 1?");
fi;
add([a[1][3], a[2]]);
else
Error("unknown case 2?");
fi;
od;
Append(res, "");
Append(res, type);
Append(res, "> \n");
return res;
end);
###########################################################################
##
## parsing BibXMLext files
##
## <#GAPDoc Label="ParseBibXMLextString">
##
##
##
## a record with fields .entries , .strings and
## .entities
##
## The first function gets a string str containing a BibXMLext
## document or a part of it. It returns a record with the three mentioned
## fields. Here .entries is a list of partial XML parse trees for
## the <entry> -elements in str . The field .strings
## is a list of key-value pairs from the <string> -elements in
## str . And .strings is a list of name-value pairs of the
## named entities which were used during the parsing.
##
##
## The optional argument res can be the result of a former call of
## this function, in that case the newly parsed entries are added to this
## data structure.
##
##
## The second function uses the first
## on the content of all files given by filenames fname1 and so on.
## It collects the results in a single record.
##
## As an example we parse the file testbib.xml shown in
## .
##
##
## gap> bib := ParseBibXMLextFiles("doc/testbib.xml");;
## gap> RecNames(bib);
## [ "entries", "strings", "entities" ]
## gap> bib.entries;
## [ <BibXMLext entry: AB2000> ]
## gap> bib.strings;
## [ [ "j", "Important Journal" ] ]
## gap> bib.entities[1];
## [ "amp", "&#38;" ]
##
##
##
## <#/GAPDoc>
##
# args: string with BibXMLext document[, record with three lists]
# the three lists n:
# .entries: parse trees of elements,
# .strings: pairs [ key, value ],
# .entities: pairs [ entity name, entity substitution ]
BindGlobal("BibXMLEntryOps", rec(
ViewObj := function(entry)
Print("");
end,
PrintObj := function(entry)
Print(StringXMLElement(entry)[1]);
end
));
MakeImmutable(BibXMLEntryOps);
# the entities from bibxmlext.dtd
BindGlobal("ENTITYDICT_bibxml", rec(
nbsp := " " ,
copyright := "©",
ndash := "–"
));
InstallGlobalFunction(ParseBibXMLextString, function(arg)
local str, res, tr, ent, strs, entries, a;
str := arg[1];
if Length(arg) > 1 then
res := arg[2];
else
res := rec(entries := [], strings := [], entities := []);
fi;
tr := ParseTreeXMLString(str, ENTITYDICT_bibxml);
# get used entities from ENTITYDICT
ent := List(RecNames(ENTITYDICT), a-> [a, ENTITYDICT.(a)]);
Append(res.entities, ent);
res.entities := Set(res.entities);
# read key value pairs
strs := XMLElements(tr, ["string"]);
for a in strs do
AddSet(res.strings, [a.attributes.key, a.attributes.value]);
od;
entries := XMLElements(tr, ["entry"]);
for a in entries do
a.operations := BibXMLEntryOps;
od;
Append(res.entries, entries);
return res;
end);
InstallGlobalFunction(ParseBibXMLextFiles, function(arg)
local res, nam, s;
if Length(arg) > 0 and not IsString(arg[Length(arg)]) then
res := arg[Length(arg)];
arg := arg{[1..Length(arg)-1]};
else
res := rec(entries := [], strings := [], entities := []);
fi;
for nam in arg do
s := StringFile(nam);
if s = fail then
Error("Cannot read file ", nam, "\n");
else
ParseBibXMLextString(StringFile(nam), res);
fi;
od;
return res;
end);
###########################################################################
##
## heuristic translation of BibTeX data to BibXMLext
##
## <#GAPDoc Label="StringBibAsXMLext">
##
##
##
## a string
##
## nothing
##
## These utilities translate some &LaTeX; code into text in UTF-8 encoding.
## The input is given as a string str , or a file name fnam ,
## respectively. The first function returns the translated string. The second
## function with one argument overwrites the given file with the translated
## text. Optionally, the translated file content can be written to another
## file, if its name is given as second argument outnam .
## The record HeuristicTranslationsLaTeX2XML mainly contains
## translations of &LaTeX; macros for special characters which were found
## in hundreds of &BibTeX; entries from
## http://www.ams.org/mathscinet/ . Just look at
## this record if you want to know how it works. It is easy to extend, and if
## you have improvements which may be of general interest, please send them
## to the &GAPDoc; author.
##
## gap> s := "\\\"u\\'{e}\\`e{\\ss}";;
## gap> Print(s, "\n");
## \"u\'{e}\`e{\ss}
## gap> Print(HeuristicTranslationsLaTeX2XML.Apply(s),"\n");
## üéèß
##
##
##
##
##
##
## a string with XML code, or fail
##
## The argument bibentry is a record representing an entry from a
## &BibTeX; file, as returned in the first list of the result of . The optional two arguments abbrvs and
## vals can be
## lists of abbreviations and substitution strings, as returned as second
## and third list element in the result of .
## The optional argument encoding specifies the character
## encoding of the string components of bibentry . If this is not
## given it is checked if all strings are valid UTF-8 encoded strings, in
## that case it is assumed that the encoding is UTF-8, otherwise the
## latin1 encoding is assumed.
##
##
## The function creates XML code of an
## <entry> -element in BibXMLext format. The result is in
## UTF-8 encoding and contains
## some heuristic translations, like splitting name lists, finding places for
## <C> -elements, putting formulae in <M> -elements,
## substituting some characters. The result should always be checked and
## maybe improved by hand. Some validity checks are applied to the given data,
## for example if all non-optional fields
## are given. If this check fails the function returns fail .
##
## If your &BibTeX; input contains &LaTeX; markup for special characters,
## it can be convenient to translate this input with or before parsing it as
## &BibTeX;.
##
## As an example we consider again the short &BibTeX; file doc/test.bib
## shown in the example for .
##
## bib := ParseBibFiles("doc/test.bib");;
## gap> str := StringBibAsXMLext(bib[1][1], bib[2], bib[3]);;
## gap> Print(str, "\n");
##
##
## Fritz A. First
## X. Y. Sec
##
## Short
##
## 2000
## ]]>
##
##
##
## <#/GAPDoc>
# args: bibrec[, abbrevs, strings][, encoding]
InstallGlobalFunction(StringBibAsXMLext, function(arg)
local r, abbrevs, texts, enc, MandC, struct, f, res, content,
cont, tmp, nams, pos, a, b, i, lbl;
r := arg[1];
if Length( arg ) > 2 then
abbrevs := arg[2];
texts := arg[3];
else
abbrevs := [ ];
texts := [ ];
fi;
if not IsSet(texts) then
SortParallel(texts, abbrevs);
fi;
if Length(arg) in [2, 4] then
enc := arg[Length(arg)];
else
# try to autodetect UTF-8, else assume latin1
if ForAny(RecNames(r), a-> IsString(r.(a)) and Unicode(r.(a)) = fail) or
ForAny(abbrevs, a-> Unicode(a) = fail) or
ForAny(texts, a-> Unicode(a) = fail) then
enc := "ISO-8859-1";
else
enc := "UTF-8";
fi;
fi;
if UNICODE_RECODE.NormalizedEncoding(enc) = fail then
Info(InfoBibTools, 1, "don't know encoding ", enc, " using ISO-8859-1\n");
enc := "ISO-8859-1";
else
enc := UNICODE_RECODE.NormalizedEncoding(enc);
fi;
if enc <> "UTF-8" then
r := ShallowCopy(r);
for a in RecNames(r) do
if IsString(r.(a)) then
r.(a) := Encode(Unicode(r.(a), enc));
fi;
od;
abbrevs := List(abbrevs, a-> Encode(Unicode(a, enc)));
texts := List(texts, a-> Encode(Unicode(a, enc)));
fi;
# helper, to change {}'s outside math mode and $'s in
# (book)title and -elements:
MandC := function(str)
local res, math, c;
if Position(str, '{') = fail and Position(str, '$') = fail then
return str;
fi;
# escape & and <
str := SubstitutionSublist(str, "<", "<");
str := SubstitutionSublist(str, "&", "&");
res := "";
math := false;
for c in str do
if c = '$' then
math := not math;
if math then
Append(res, "");
else
Append(res, " ");
fi;
elif c = '{' and not math then
Append(res, "");
elif c = '}' and not math then
Append(res, " ");
else
Add(res, c);
fi;
od;
return ParseTreeXMLString(res).content;
end;
if not (r.Type in RecNames(BibXMLextStructure)) then
Info(InfoBibTools, 1, "#W WARNING: invalid .Type in Bib-record: ",
r.Type, "\n");
Info(InfoBibTools, 2, r, "\n");
return fail;
fi;
struct := BibXMLextStructure.(r.Type);
f := RecNames(r);
if "Label" in f then
lbl:= Concatenation( " (", r.Label, ") " );
else
lbl:= "";
fi;
# checking conditions on certain related elements in an entry
if "isbn" in f and "issn" in f then
Info(InfoBibTools, 1, "#W WARNING: Cannot have both, ISBN and ISSN ",
"in Bib-record", lbl, "\n");
Info(InfoBibTools, 2, r, "\n");
return fail;
fi;
if r.Type in ["book", "inbook", "incollection", "proceedings",
"inproceedings", "conference"] and
"volume" in f and "number" in f then
Info(InfoBibTools, 1, "#W WARNING: Cannot have both in ",
r.Type, "-entry, 'volume' and 'number'", lbl, "\n");
Info(InfoBibTools, 2, r, "\n");
return fail;
fi;
if r.Type in ["book", "inbook"] then
if "author" in f and "editor" in f then
Info(InfoBibTools, 1, "#W WARNING: Cannot have both in ",
r.Type, "-entry, 'author' and 'editor'", lbl, "\n");
Info(InfoBibTools, 2, r, "\n");
return fail;
elif not "author" in f and not "editor" in f then
Info(InfoBibTools, 1, "#W WARNING: Must have 'author' or 'editor' in ",
r.Type, "-entry", lbl, "\n");
Info(InfoBibTools, 2, r, "\n");
return fail;
fi;
fi;
if r.Type = "inbook" then
if not "pages" in f then
if not "chapter" in f then
Info(InfoBibTools, 1,"#W WARNING: Must have 'chapter' and/or 'pages' ",
"in inbook-entry", lbl, "\n");
Info(InfoBibTools, 2, r, "\n");
return fail;
fi;
fi;
fi;
# now we can flatten struct
struct := Concatenation(List(struct, function(a) if not IsString(a[1]) then
return List(Filtered(a[1], x-> x<>"or"),
b-> [b, false]); else return [a]; fi; end));
# now construct the result, first as XML tree
res := rec(name := "entry", attributes := rec(id := r.Label),
content := [rec(name := r.Type, attributes := rec(), content := [])]);
cont := res.content[1].content;
for a in struct do
if a[2] = true and not a[1] in f then
Info(InfoBibTools, 1, "#W WARNING: Must have '", a[1], "' in ",
r.Type, "-entry", lbl, "\n");
Info(InfoBibTools, 2, r, "\n");
return fail;
fi;
if a[1] in f then
Add(cont, "\n ");
# special handling of author/editor
if a[1] in ["author", "editor"] and IsString(r.(a[1])) then
tmp := rec(name := a[1], attributes := rec(), content := ["\n "]);
nams := NormalizedNameAndKey(r.(a[1]));
for b in nams[4] do
Add(tmp.content, " ");
Add(tmp.content, rec(name := "name", attributes := rec(),
content := [ rec(name := "first", attributes := rec(),
content := b[3]),
rec(name := "last", attributes := rec(),
content := b[1]) ] ));
Add(tmp.content, "\n ");
od;
Add(cont, tmp);
Add(cont, " ");
else
if IsRecord(r.(a[1])) then
Add(cont, r.(a[1]));
else # string
if a[1] in ["title", "booktitle"] then
tmp := MandC(r.(a[1]));
else
tmp := r.(a[1]);
pos := PositionSet(texts, tmp);
if pos <> fail then
tmp := [rec(name := "value", attributes := rec(key :=
abbrevs[pos]), content := 0)];
fi;
fi;
Add(cont, rec(name := a[1], attributes := rec(), content := tmp));
fi;
fi;
fi;
od;
# additional infos
f := Difference(f, List(struct, a-> a[1]));
f := Filtered(f, a-> not a in ["From", "Type", "Label"]);
for a in f do
Add(cont, "\n ");
Add(cont, rec(name := "other", attributes := rec( type := a ),
content := r.(a)) );
od;
Add(cont, "\n");
res := StringXMLElement(res)[1];
res := SplitString(res, "\n", "");
for i in [1..Length(res)] do
if Length(res[i]) > 76 then
a := FormatParagraph(res[i], 76, "left", [" ",""]);
Unbind(a[Length(a)]);
a := a{[5..Length(a)]};
res[i] := a;
fi;
od;
return JoinStringsWithSeparator(res, "\n");
end);
# Heuristic LaTeX to BibXML markup translations
InstallValue(HeuristicTranslationsLaTeX2XML, rec(
CharacterMarkup := [
["\\accent127", "\\\""],
["{\\\"a}", "ä"],
["{\\\"{a}}", "ä"],
["\\\"a", "ä"],
["\\\"{a}", "ä"],
["{\\\"A}", "Ä",],
["\\\"A", "Ä"],
["{\\'a}", "á"],
["\\'a", "á"],
["{\\'A}", "Á"],
["\\'A", "Á"],
["\\`a", "à"],
["{\\d{a}}", "ạ"],
[ "\\=a", "ā" ], # 257
[ "{\\aa}", "å" ], # 229
[ "{\\AA}", "Å" ], # 197
[ "\\AA", "Å" ], # 197
[ "{\\u{a}}", "ă" ], # 259
[ "{\\c{c}}", "ç" ], # 231
[ "{\\'c}", "ć" ], # 263
[ "{\\v{c}}", "č" ], # 269
[ "{\\Dbar}", "Ð" ], # 208, defined in preamble
["\\'E", "É"],
[ "{\\\"e}", "ë" ], # 235
[ "\\\"e", "ë" ], # 235
[ "{\\^e}", "ê" ], # 234
[ "\\^e", "ê" ], # 234
["{\\'e}", "é"],
["{\\`e}", "è"],
["\\'e", "é"],
["\\`e", "è"],
["\\'{e}", "é"],
["\\`{e}", "è"],
["\\'{E}", "É"],
["{\\`E}", "È"],
["\\`{E}", "È"],
["{\\v{e}}", "ě"],
[ "{\\u{g}}", "ğ" ], # 287
[ "{\\'{\\i}}", "í" ], # 237
[ "{\\'{\\i}}", "í" ], # 237
[ "{\\'\\i}", "í" ], # 237
[ "\\'\\i ", "í" ], # 237
[ "{\\u\\i}", "ĭ" ], # 301, must come before the next line!
["\\u\\i", "ĭ"],
[ "{\\={\\i}}", "ī" ], # 299
[ "{\\i}", "ı" ], # 305
[ "{\\'n}", "ń" ], # 324
[ "{\\~n}", "ñ" ], # 241
[ "\\~n", "ñ" ], # 241
[ "{\\tilde n}", "ñ" ], # 241
[ "\\tilde n", "ñ" ], # 241
["{\\\"o}", "ö"],
["{\\\"O}", "Ö"],
["\\\"o", "ö"],
["\\\"O", "Ö"],
["{\\'o}", "ó"],
["{\\'O}", "Ó"],
["\\'o", "ó"],
[ "\\=o", "ō" ], # 333
[ "{\\H{O}}", "Ő" ], # 336
[ "{\\H o}", "ő" ], # 337
[ "{\\H{o}}", "ő" ], # 337
[ "\\H o", "ő" ], # 337
[ "\\^o", "ô" ], # 244
[ "\\^u", "û" ], # 251
[ "{\\o}", "ø" ], # 248
[ "{\\.P}", "Ṗ" ], # 0x1E56
[ "{\\. P}", "Ṗ" ], # 0x1E56
[ "{\\v{s}}", "š" ], # 353
[ "{\\c{S}}", "Ş" ], # 350
[ "{\\v{S}}", "Š" ], # 352
[ "{\\'s}", "ś" ],
["{\\\"u}", "ü"],
["{\\\"U}", "Ü"],
["\\\"{U}", "Ü"],
["\\\"u", "ü"],
["\\\"U", "Ü"],
["{\\\"{u}}", "ü"],
["\\\"{u}", "ü"],
[ "{\\'u}", "ú" ], # 250
[ "\\'u", "ú" ], # 250
[ "{\\H{U}}", "Ű" ], # 368
[ "{\\H{u}}", "ű" ], # 369
[ "\\=u", "ū" ], # 363
[ "\\=u", "ū" ], # 363
["{\\'y}", "ý"],
["\\v Z", "Ž"],
[ "{\\v{Z}}", "Ž" ], # 381
["{\\ss}", "ß"],
[ "\\ss ", "ß" ],
[ "\\eta", "η" ], # 951
[ "\\mu", "μ" ], # 956
[ "\\pm", "±" ], # 177
["\\sb ", "_" ],
["\\sb\n", "_" ],
["\\sb{", "_{"],
["\\sp ", "^" ],
["\\sp\n", "^" ],
["\\sp{", "^{"],
["\\#", "#"],
["\\&", "&"],
["\\ ", " "],
["$'$", "ʹ"],
["{\\cprime}", "ʹ"],
[ "\\cprime ", "ʹ" ],
[ "\\cprime,", "ʹ," ],
["{\\etalchar{+}}", "+"],
["---", "—"], # —
["--", "–"], # –
#T The following occurs once in the GAP bibliography,
# inside an authors' name.
[ "{-}", "-" ], # ???
#T The following occurs in Gri87a, in a cross-reference inside the TITLE
#T (which is a bad idea ...)
[ "[{\\it ", "[{" ],
# more heuristics:
[ "\\\n", "" ], # remove \ together with a following line break
[ " _", "_" ],
[ "_ ", "_" ],
[ " ^", "^" ],
[ "^ ", "^" ],
[ "\\times", " \\times " ],
[ " \\times", " \\times" ],
[ "\\times ", "\\times " ],
[ "\\cdot", " \\cdot " ],
[ "\\cdot", " \\cdot " ],
[ " \\cdot", " \\cdot" ],
[ "\\cdot ", "\\cdot " ],
[ "\\sf\n", "\\sf " ],
# delete hyphenation hints, should be done by end user
[ "\\-", "" ]
],
RepeatedTranslations:= [
[ "_ ", "_" ],
[ "^ ", "^" ],
[ "\\sf ", "\\sf " ],
],
TranslationsOfPairs := [
[ "\\sqrt{", "}", "\\sqrt{{", "}}" ],
[ "\\sqrt{{{", "}}}", "\\sqrt{{", "}}" ],
[ "^{", "}", "^{{", "}}" ],
[ "^{{{", "}}}", "^{{", "}}" ],
[ "_{", "}", "_{{", "}}" ],
[ "_{{{", "}}}", "_{{", "}}" ],
],
## replace ... by ...
#T would of course be better to prescribe a MATCHING of brackets ...
TranslationOfOnePair:= function( str, start, eend, rstart, rend )
local pos, pos2;
pos:= 0;
while pos <> fail do
pos:= PositionSublist( str, start, pos );
if pos <> fail then
pos2:= PositionSublist( str, eend, pos );
if pos2 = fail then
Error( "no match!" );
fi;
str:= Concatenation( str{ [ 1 .. pos -1 ] }, rstart,
str{ [ pos+Length( start ) .. pos2-1 ] },
rend,
str{ [ pos2+Length( eend ) .. Length( str ) ] } );
fi;
od;
return str;
end,
));
# SubstitutionSublist is not good enough when a pure macro must be
# substituted (don't substitute \pm in \pmod).
HeuristicTranslationsLaTeX2XML.subsTeXMacro := function(str, old, new)
local i, p, nstr, p1, p2;
# check if old ends in macro
i := Length(old);
while i > 0 and old[i] in LETTERS do
i := i-1;
od;
if i < Length(old) and old[i] = '\\' then
p := PositionSublist(str, old);
if p = fail then return str; fi;
nstr := "";
p1 := 1;
p2 := p;
while p2 <> fail do
if Length(str)=p2+Length(old)-1 or not str[p2+Length(old)] in LETTERS then
Append(nstr, str{[p1..p2-1]});
Append(nstr, new);
p1 := p2+Length(old);
fi;
p2 := PositionSublist(str, old, p2);
od;
Append(nstr, str{[p1..Length(str)]});
return nstr;
else
return SubstitutionSublist(str, old, new);
fi;
end;
HeuristicTranslationsLaTeX2XML.Apply := function(str)
local str2, pair, entry, s;
s := HeuristicTranslationsLaTeX2XML.subsTeXMacro;
for pair in HeuristicTranslationsLaTeX2XML.CharacterMarkup do
str:= s( str, pair[1], pair[2] );
od;
for pair in HeuristicTranslationsLaTeX2XML.RepeatedTranslations do
str2:= s( str, pair[1], pair[2] );
while str2 <> str do
str:= str2;
str2:= s( str, pair[1], pair[2] );
od;
od;
for entry in HeuristicTranslationsLaTeX2XML.TranslationsOfPairs do
str:= HeuristicTranslationsLaTeX2XML.TranslationOfOnePair( str, entry[1],
entry[2], entry[3], entry[4] );
od;
return str;
end;
HeuristicTranslationsLaTeX2XML.ApplyToFile := function(arg)
local fnam, outnam, str;
fnam := arg[1];
if Length(arg) > 1 then
outnam := arg[2];
else
outnam := fnam;
fi;
str := StringFile(fnam);
str := HeuristicTranslationsLaTeX2XML.Apply(str);
FileString(outnam, str);
end;
## <#GAPDoc Label="WriteBibXMLextFile">
##
##
## nothing
##
## This function writes a BibXMLext file with name fname .
##
## There are three possibilities to specify the bibliography entries in the
## argument bib . It can be a list of three lists as returned by . Or it can be just the first of such three lists
## in which case the other two lists are assumed to be empty. To all
## entries of the (first) list the function
## is applied and the resulting strings are written to the result file.
##
## The third possibility is that bib is a record in the
## format as returned by and . In this case the entries for the
## BibXMLext file are produced with ,
## and if bib .entities is bound then it is tried to
## resubstitute parts of the string by the given entities with .
##
## As an example we write back the result of the example shown for
## to an equivalent XML file.
##
##
## gap> bib := ParseBibXMLextFiles("doc/testbib.xml");;
## gap> WriteBibXMLextFile("test.xml", bib);
##
##
##
## <#/GAPDoc>
InstallGlobalFunction(WriteBibXMLextFile, function(fname, bib)
local i, a, s, f, strstr;
f := OutputTextFile(fname, false);
SetPrintFormattingStatus(f, false);
PrintTo(f, "\n",
"\n",
"\n");
# a helper
strstr := function(key, val)
return StringXMLElement(rec(name := "string", attributes := rec(
key := key, value := val), content := 0))[1];
end;
# make sure, strings are sorted
if IsList(bib) then
if not IsRecord(bib[1]) then
bib := ShallowCopy(bib);
bib[2] := ShallowCopy(bib[2]);
bib[3] := ShallowCopy(bib[3]);
else
bib := [bib, [], []];
fi;
# strings first
for i in [1..Length(bib[2])] do
AppendTo(f, strstr(bib[2][i], bib[3][i]), "\n");
od;
SortParallel(bib[3], bib[2]);
for a in bib[1] do
AppendTo(f, StringBibAsXMLext(a, bib[2], bib[3]), "\n");
od;
else
if IsBound(bib.strings) then
for a in bib.strings do
AppendTo(f, strstr(a[1], a[2]), "\n");
od;
fi;
for a in bib.entries do
s := StringXMLElement(a);
if IsBound(bib.entities) then
s := EntitySubstitution(s, bib.entities);
fi;
AppendTo(f, s, "\n");
od;
fi;
AppendTo(f, " \n");
end);
###########################################################################
##
## translating BibXML entries to records
##
##
## <#GAPDoc Label="RecBibXMLEntry">
##
##
## a record with fields as strings
##
## This function generates a content string for each field of a
## bibliography entry and assigns them to record components. This content
## may depend on the requested result type and possibly some given options.
##
##
## The arguments are as follows: entry is the parse
## tree of an <entry> element as returned by or .
## The optional argument restype describes the type of the
## result. This package supports currently the types "BibTeX" ,
## "Text" and "HTML" . The default is "BibTeX" . The
## optional argument strings must be a list of key-value pairs as
## returned in the component .strings in the result of . The argument options must be a
## record.
##
## If the entry contains an author field then the result will also
## contain a component .authorAsList which is a list containing for
## each author a list with three entries of the form [last name, first
## name initials, first name] (the third entry means the first name as
## given in the data). Similarly, an editor field is accompanied by
## a component .editorAsList .
##
## The following options are currently supported.
##
## If options.fullname is bound and set to true then the full
## given first names for authors and editors will be used, the default is
## to use the initials of the first names. Also, if
## options.namefirstlast is bound and set to true then the
## names are written in the form first-name(s) last-name , the
## default is the form last-name, first-name(s) .
##
## If options.href is bound and set to false then the
## "BibTeX" type result will not use \href commands.
## The default is to produce \href commands from
## <URL> -elements such that &LaTeX; with the hyperref
## package can produce links for them.
##
## The content of an <Alt> -element with Only -attribute is
## included if restype is given in the attribute and ignored
## otherwise, and vice versa in case of a Not -attribute. If
## options.useAlt is bound, it must be a list of strings
## to which restype is added. Then an <Alt> -element
## with Only -attribute is evaluated if the intersection of
## options.useAlt and the types given in the attribute is not empty.
## In case of a Not -attribute the element is evaluated if this
## intersection is empty.
##
## If restype is "BibTeX" then the string fields in the
## result will be recoded with and target
## "LaTeX" . If options.hasLaTeXmarkup is bound and set to
## true (for example, because the data are originally read from
## &BibTeX; files), then the target "LaTeXleavemarkup" will be
## used.
##
## We use again the file shown in the example for .
##
## gap> bib := ParseBibXMLextFiles("doc/testbib.xml");;
## gap> e := bib.entries[1];; strs := bib.strings;;
## gap> Print(RecBibXMLEntry(e, "BibTeX", strs), "\n");
## rec(
## From := rec(
## BibXML := true,
## options := rec(
## ),
## type := "BibTeX" ),
## Label := "AB2000",
## Type := "article",
## author := "First, F. A. and Sec{\\H o}nd, X. Y.",
## authorAsList :=
## [ [ "First", "F. A.", "Fritz A." ],
## [ "Sec\305\221nd", "X. Y.", "X. Y." ] ],
## journal := "Important Journal",
## mycomment := "very useful",
## note :=
## "Online data at \\href {http://www.publish.com/~ImpJ/123#data} {Bla\
## Bla Publisher}",
## number := "13",
## pages := "13{\\textendash}25",
## printedkey := "FS00",
## title :=
## "The {F}ritz package for the \n formula $x^y - l_{{i+1}} \
## \\rightarrow \\mathbb{R}$",
## year := "2000" )
## gap> Print(RecBibXMLEntry(e, "HTML", strs).note, "\n");
## Online data at <a href="http://www.publish.com/~ImpJ/123#data">Bla Bla\
## Publisher</a>
##
##
##
## <#/GAPDoc>
## <#GAPDoc Label="AddHandlerBuildRecBibXMLEntry">
##
##
## nothing
##
## The argument elementname must be the name of an entry field
## supported by the BibXMLext format, the name of one of the special
## elements "C" , "M" , "Math" , "URL" or of the
## form "Wrap:myname" or any string "mytype" (which then
## corresponds to entry fields <other type="mytype"> ). The string
## "Finish" has an exceptional meaning, see below.
##
## restype is a string describing the result type for which the
## handler is installed, see .
##
## For both arguments, elementname and restype , it is also
## possible to give lists of the described ones for installing several
## handler at once.
##
## The argument handler must be a function with five
## arguments of the form handler (entry, r, restype, strings,
## options) . Here entry is a parse tree of a BibXMLext
## <entry> -element, r is a node in this tree for an
## element elementname , and restype , strings and
## options are as explained in .
## The function should return a string representing the content
## of the node r . If elementname is of the form
## "Wrap:myname" the handler is used for elements of form
## <Wrap Name="myname">...</Wrap> .
##
## If elementname is "Finish" the handler should look like
## above except that now r is the record generated by just before it is returned. Here the handler
## should return nothing. It can be used to manipulate the record r ,
## for example for changing the encoding of the strings or for adding some
## more components.
##
## The installed handler is called by
## BuildRecBibXMLEntry( entry , r , restype ,
## strings , options ) . The string for the
## whole content of an element can be generated
## by ContentBuildRecBibXMLEntry( entry , r ,
## restype , strings , options ) .
##
## We continue the example from and install a
## handler for the <Wrap Name="Package"> -element such that
## &LaTeX; puts its content in a sans serif font.
##
## gap> AddHandlerBuildRecBibXMLEntry("Wrap:Package", "BibTeX",
## > function(entry, r, restype, strings, options)
## > return Concatenation("\\textsf{", ContentBuildRecBibXMLEntry(
## > entry, r, restype, strings, options), "}");
## > end);
## gap>
## gap> Print(RecBibXMLEntry(e, "BibTeX", strs).title, "\n");
## The \textsf{ {F}ritz} package for the
## formula $x^y - l_{{i+1}} \rightarrow \mathbb{R}$
## gap> Print(RecBibXMLEntry(e, "Text", strs).title, "\n");
## The Fritz package for the
## formula x^y - l_{i+1} → R
## gap> AddHandlerBuildRecBibXMLEntry("Wrap:Package", "BibTeX", "Ignore");
##
##
##
## <#/GAPDoc>
InstallGlobalFunction(ContentBuildRecBibXMLEntry,
function(entry, elt, type, strings, opts)
local res, a;
res := "";
for a in elt.content do
Append(res, BuildRecBibXMLEntry(entry, a, type, strings, opts));
od;
return res;
end);
InstallGlobalFunction(BuildRecBibXMLEntry,
function(entry, elt, type, strings, opts)
local letters, res, f, nam, nams, key, hdlr, a;
# helper to find a key
letters := function(str, one)
local pos;
str := Unicode(str, "UTF-8");
if UChar(' ') in str then
pos := Concatenation([1], 1+Positions(str, UChar(' ')));
if one then
return Encode(str{[pos[Length(pos)]]}, "UTF-8");
else
return Encode(str{pos}, "UTF-8");
fi;
else
if one then
pos := Minimum(1, Length(str));
else
pos := Minimum(3, Length(str));
fi;
return Encode(str{[1..pos]}, "UTF-8");
fi;
end;
if elt = entry then
# upper level, create result record
res := rec(From := rec(BibXML := true, type := type, options := opts));
res.Label := entry.attributes.id;
f := First(entry.content, a-> IsRecord(a) and a.name in
RecNames(BibXMLextStructure));
res.Type := f.name;
for a in f.content do
if IsRecord(a) and not a.name = "PCDATA" then
nam := a.name;
if nam in ["author", "editor"] then
res.(Concatenation(nam, "AsList")) :=
BuildRecBibXMLEntry(entry, a, "namesaslists", strings, opts);
fi;
if nam = "other" then
nam := a.attributes.type;
fi;
res.(nam) := BuildRecBibXMLEntry(entry, a, type, strings, opts);
fi;
od;
# we produce a key if not given
if not IsBound(res.key) then
if IsBound(res.authorAsList) then
nams := res.authorAsList;
elif IsBound(res.editorAsList) then
nams := res.editorAsList;
else
nams := 0;
fi;
if nams = 0 then
key := "NOAUTHOROREDITOR_SPECIFYKEY";
else
key := "";
if Length(nams) = 1 then
Append(key, letters(nams[1][1], false));
else
for a in nams do
Append(key, letters(a[1], true));
od;
fi;
if IsBound(res.year) and Length(res.year) >= 2 then
Append(key, res.year{[Length(res.year)-1, Length(res.year)]});
fi;
fi;
res.printedkey := key;
fi;
# a possibility for some final cleanup/additions, e.g., for handling
# some options
if IsBound(RECBIBXMLHNDLR.Finish.(type)) then
res := RECBIBXMLHNDLR.Finish.(type)(entry, res, type, strings, opts);
fi;
return res;
else
# return a string (or something else if you know what you are doing)
# call this function recursively
if IsString(elt) then
# end of recursion
return elt;
fi;
nam := elt.name;
if IsBound(RECBIBXMLHNDLR.(nam)) then
hdlr := RECBIBXMLHNDLR.(nam); else
hdlr := RECBIBXMLHNDLR.default;
fi;
if IsBound(hdlr.(type)) then
hdlr := hdlr.(type);
elif IsBound(hdlr.default) then
hdlr := hdlr.default;
else
hdlr := RECBIBXMLHNDLR.default.default;
fi;
return hdlr(entry, elt, type, strings, opts);
fi;
end);
# eltname can be an elementname or a list of elementnames, in the latter
# case fun is installed for all of them, same with type
InstallGlobalFunction(AddHandlerBuildRecBibXMLEntry,
function(eltname, type, fun)
local e;
if not IsString(eltname) and IsList(eltname) then
for e in eltname do
AddHandlerBuildRecBibXMLEntry(e, type, fun);
od;
return;
fi;
if not IsString(type) and IsList(type) then
for e in type do
AddHandlerBuildRecBibXMLEntry(eltname, e, fun);
od;
return;
fi;
if not IsBound(RECBIBXMLHNDLR.(eltname)) then
RECBIBXMLHNDLR.(eltname) := rec();
fi;
if fun = "Ignore" then
fun := RECBIBXMLHNDLR.default.default;
fi;
RECBIBXMLHNDLR.(eltname).(type) := fun;
end);
# this just collect text recursively
AddHandlerBuildRecBibXMLEntry("default", "default",
function(entry, elt, type, strings, opts)
if IsString(elt.content) then
return elt.content;
elif elt.content = 0 then
return "";
else
return ContentBuildRecBibXMLEntry(entry, elt, type, strings, opts);
fi;
end);
# dealing with names in author and editor fields
# helper function, find initials from UTF-8 string, keep '-'s
RECBIBXMLHNDLR.Initials := function(fnam)
local pre, res, i;
fnam := NormalizedWhitespace(fnam);
fnam := Unicode(fnam, "UTF-8");
pre := Unicode(" -");
res := Unicode("");
for i in [1..Length(fnam)] do
if i=1 or fnam[i-1] in pre then
Add(res, fnam[i]);
Add(res, UChar('.'));
elif fnam[i] in pre then
Add(res, fnam[i]);
fi;
od;
return Encode(res, "UTF-8");
end;
# produce the names as lists (result will be bound to elt.AsList
# before 'author' and 'editor' are produced)
AddHandlerBuildRecBibXMLEntry("name", "namesaslists",
function(entry, elt, type, strings, opts)
local res, f;
res := [];
f := First(elt.content, a-> IsRecord(a) and a.name = "last");
Add(res, BuildRecBibXMLEntry(entry, f, type, strings, opts));
NormalizeWhitespace(res[1]);
f := First(elt.content, a-> IsRecord(a) and a.name = "first");
if f <> fail then
res[3] := BuildRecBibXMLEntry(entry, f, type, strings, opts);
NormalizeWhitespace(res[3]);
res[2] := RECBIBXMLHNDLR.Initials(res[3]);
fi;
return res;
end);
AddHandlerBuildRecBibXMLEntry(["author", "editor"], "namesaslists",
function(entry, elt, namesaslists, strings, opts)
local res, a;
res := [];
RECBIBXMLHNDLR.recode := false;
for a in elt.content do
if IsRecord(a) and a.name = "name" then
Add(res, BuildRecBibXMLEntry(entry, a, namesaslists, strings, opts));
fi;
od;
RECBIBXMLHNDLR.recode := true;
elt.AsList := res;
return res;
end);
# a helper
RECBIBXMLHNDLR.namstringlist := function(l, opts)
local res, f, a;
res := [];
for a in l do
if Length(a) = 1 then
Add(res, a[1]);
else
if IsBound(opts.fullname) and opts.fullname = true then
f := a[3];
else
f := a[2];
fi;
if IsBound(opts.namefirstlast) and opts.namefirstlast = true then
Add(res, Concatenation(f, " ", a[1]));
else
Add(res, Concatenation(a[1], ", ", f));
fi;
fi;
od;
return res;
end;
# now the default (BibTeX) version
AddHandlerBuildRecBibXMLEntry(["author", "editor"], "default",
function(entry, elt, default, strings, opts)
local res, a;
res := RECBIBXMLHNDLR.namstringlist(elt.AsList, opts);
res := JoinStringsWithSeparator(res, " and ");
if IsBound(opts.hasLaTeXmarkup) and opts.hasLaTeXmarkup = true then
return Encode(Unicode(res), "LaTeXleavemarkup");
else
return Encode(Unicode(res), "LaTeX");
fi;
end);
# and Text and HTML with only one 'and'
AddHandlerBuildRecBibXMLEntry(["author", "editor"], ["Text", "HTML"],
function(entry, elt, default, strings, opts)
local res, f, a;
res := RECBIBXMLHNDLR.namstringlist(elt.AsList, opts);
if Length(res) > 2 then
res := [JoinStringsWithSeparator(res{[1..Length(res)-1]}, ", "),
res[Length(res)]];
fi;
return JoinStringsWithSeparator(res, " and ");
end);
# now the special markup elements
#
AddHandlerBuildRecBibXMLEntry("C", "default",
function(entry, elt, default, strings, opts)
return Concatenation("{", ContentBuildRecBibXMLEntry(entry, elt,
default, strings, opts), "}");
end);
AddHandlerBuildRecBibXMLEntry("C", ["Text", "HTML"], "Ignore");
# ,
AddHandlerBuildRecBibXMLEntry(["M", "Math"], "default",
function(entry, elt, default, strings, opts)
local res;
if IsBound(opts.MathJax) and opts.MathJax = true then
return RECBIBXMLHNDLR.M.MathJax(entry, elt, default, strings, opts);
fi;
RECBIBXMLHNDLR.recode := false;
res := Concatenation("$", ContentBuildRecBibXMLEntry(entry, elt,
default, strings, opts), "$");
RECBIBXMLHNDLR.recode := true;
return res;
end);
AddHandlerBuildRecBibXMLEntry("M", "HTML",
function(entry, elt, default, strings, opts)
local res;
if IsBound(opts.MathJax) and opts.MathJax = true then
return RECBIBXMLHNDLR.M.MathJax(entry, elt, default, strings, opts);
fi;
RECBIBXMLHNDLR.recode := false;
res := TextM( ContentBuildRecBibXMLEntry(entry, elt, default, strings, opts));
RECBIBXMLHNDLR.recode := true;
res := SubstitutionSublist(res, "&", "&");
res := SubstitutionSublist(res, "<", "<");
return res;
end);
AddHandlerBuildRecBibXMLEntry("M", "MathJax",
function(entry, elt, default, strings, opts)
local res;
RECBIBXMLHNDLR.recode := false;
res := Concatenation("\\(",
ContentBuildRecBibXMLEntry(entry, elt, default, strings, opts),
"\\)");
RECBIBXMLHNDLR.recode := true;
res := SubstitutionSublist(res, "&", "&");
res := SubstitutionSublist(res, "<", "<");
return res;
end);
AddHandlerBuildRecBibXMLEntry("M", "Text",
function(entry, elt, default, strings, opts)
return TextM( ContentBuildRecBibXMLEntry(entry, elt, default, strings, opts));
end);
#
AddHandlerBuildRecBibXMLEntry("value", "default",
function(entry, elt, default, strings, opts)
local pos;
pos := PositionSorted(strings, [elt.attributes.key]);
if not IsBound(strings[pos]) or strings[pos][1] <> elt.attributes.key then
return Concatenation("UNKNOWNVALUE(", elt.attributes.key, ")");
else
return BuildRecBibXMLEntry(entry, rec(name := "PCDATA",
content := strings[pos][2]), default, strings, opts);
fi;
end);
#
AddHandlerBuildRecBibXMLEntry("URL", "default",
function(entry, elt, default, strings, opts)
local f, txt, res, lopt;
f := First(elt.content, a-> a.name = "LinkText");
if f <> fail then
txt := ContentBuildRecBibXMLEntry(entry, f, default, strings, opts);
f := First(elt.content, a-> a.name = "Link");
if f = fail then
Error("#I : either use content and 'Text' attribute of elements ",
"\n#I and .\n");
else
RECBIBXMLHNDLR.recode := false;
res := ContentBuildRecBibXMLEntry(entry, f, default, strings, opts);
RECBIBXMLHNDLR.recode := true;
fi;
else
RECBIBXMLHNDLR.recode := false;
res := ContentBuildRecBibXMLEntry(entry, elt, default, strings, opts);
RECBIBXMLHNDLR.recode := true;
NormalizeWhitespace(res);
if IsBound(opts.hasLaTeXmarkup) and opts.hasLaTeXmarkup = true then
lopt := "LaTeXleavemarkup";
else
lopt := "LaTeX";
fi;
if IsBound(elt.attributes.Text) then
txt := Encode(Unicode(elt.attributes.Text), lopt);
else
txt := Encode(Unicode(res), lopt);
txt := Concatenation("\\texttt{", txt, "}");
# allow hyphenation of long entries without hyphen dash
txt := GAPDoc2LaTeXProcs.URLBreaks(txt);
fi;
fi;
if IsBound(opts.href) and opts.href = false then
if res <> txt then
txt := Concatenation(txt, " (", res, ")");
fi;
return txt;
fi;
return Concatenation("\\href {", res, "} {", txt, "}");
end);
AddHandlerBuildRecBibXMLEntry("URL", "HTML",
function(entry, elt, html, strings, opts)
local f, txt, res;
f := First(elt.content, a-> a.name = "LinkText");
if f <> fail then
txt := ContentBuildRecBibXMLEntry(entry, f, html, strings, opts);
f := First(elt.content, a-> a.name = "Link");
if f = fail then
Error("#I : either use content and 'Text' attribute of elements ",
"\n#I and .\n");
else
RECBIBXMLHNDLR.recode := false;
res := ContentBuildRecBibXMLEntry(entry, f, html, strings, opts);
RECBIBXMLHNDLR.recode := true;
fi;
else
RECBIBXMLHNDLR.recode := false;
res := ContentBuildRecBibXMLEntry(entry, elt, html, strings, opts);
RECBIBXMLHNDLR.recode := true;
NormalizeWhitespace(res);
if IsBound(elt.attributes.Text) then
txt := elt.attributes.Text;
else
txt := res;
fi;
txt := SubstitutionSublist(txt, "&", "&");
txt := SubstitutionSublist(txt, "<", "<");
fi;
return Concatenation("", txt, " ");
end);
AddHandlerBuildRecBibXMLEntry("URL", "Text",
function(entry, elt, text, strings, opts)
local f, txt, res;
f := First(elt.content, a-> a.name = "LinkText");
if f <> fail then
txt := ContentBuildRecBibXMLEntry(entry, f, text, strings, opts);
f := First(elt.content, a-> a.name = "Link");
if f = fail then
Error("#I : either use content and 'Text' attribute of elements ",
"\n#I and .\n");
else
res := ContentBuildRecBibXMLEntry(entry, f, text, strings, opts);
NormalizeWhitespace(res);
fi;
else
res := ContentBuildRecBibXMLEntry(entry, elt, text, strings, opts);
NormalizeWhitespace(res);
if IsBound(elt.attributes.Text) then
txt := elt.attributes.Text;
else
txt := res;
fi;
fi;
if txt = res then
return res;
else
return Concatenation(txt, " (", res, ")");
fi;
end);
AddHandlerBuildRecBibXMLEntry("Alt", "default",
function(entry, elt, type, strings, opts)
local poss, att, ok, res;
poss := [type];
if IsBound(opts.useAlt) then
Append(poss, opts.useAlt);
fi;
att := elt.attributes;
if IsBound(att.Only) then
ok := SplitString(att.Only, "", ", \n\r\t");
else
ok := SplitString(att.Not, "", ", \n\r\t");
fi;
if (IsBound(att.Only) and ForAny(poss, a-> a in ok)) then
RECBIBXMLHNDLR.recode := false;
res := ContentBuildRecBibXMLEntry(entry, elt, type, strings, opts);
RECBIBXMLHNDLR.recode := true;
return res;
elif (IsBound(att.Not) and ForAll(poss, a-> not a in ok)) then
return ContentBuildRecBibXMLEntry(entry, elt, type, strings, opts);
else
return "";
fi;
end);
AddHandlerBuildRecBibXMLEntry("Wrap", "default",
function(entry, elt, type, strings, opts)
local n, hdlr, res, a;
n := Concatenation("Wrap:", elt.attributes.Name);
hdlr := fail;
if IsBound(RECBIBXMLHNDLR.(n)) then
if IsBound(RECBIBXMLHNDLR.(n).(type)) then
hdlr := RECBIBXMLHNDLR.(n).(type);
elif IsBound(RECBIBXMLHNDLR.(n).default) then
hdlr := RECBIBXMLHNDLR.(n).default;
fi;
fi;
if hdlr = fail then
# default is to ignore the markup
return ContentBuildRecBibXMLEntry(entry, elt, type, strings, opts);
else
return hdlr(entry, elt, type, strings, opts);
fi;
end);
RECBIBXMLHNDLR.Finish := rec();
# Finish functions
AddHandlerBuildRecBibXMLEntry("Finish", ["BibTeX", "LaTeX"],
function(entry, res, type, strings, opts)
if IsBound(res.printedkey) then
res.printedkey := Encode(Unicode(res.printedkey), "LaTeX");
fi;
return res;
end);
RECBIBXMLHNDLR.recode := true;
AddHandlerBuildRecBibXMLEntry("PCDATA", ["BibTeX", "LaTeX"],
function(entry, elt, type, strings, opts)
local lopt;
if RECBIBXMLHNDLR.recode then
if IsBound(opts.hasLaTeXmarkup) and opts.hasLaTeXmarkup = true then
lopt := "LaTeXleavemarkup";
else
lopt := "LaTeX";
fi;
return Encode(Unicode(elt.content, "UTF-8"), lopt);
else
return elt.content;
fi;
end);
AddHandlerBuildRecBibXMLEntry("PCDATA", "HTML",
function(entry, elt, type, strings, opts)
local res;
if RECBIBXMLHNDLR.recode then
res := SubstitutionSublist(elt.content, "<", "<");
return SubstitutionSublist(res, "&", "&");
else
return elt.content;
fi;
end);
# args:
# xml tree of entry[, type][, strings (as list of pairs)][, options record]
InstallGlobalFunction(RecBibXMLEntry, function(arg)
local entry, type, strings, opts, res, i;
entry := arg[1];
RECBIBXMLHNDLR.recode := true;
type := fail; strings := fail; opts := fail;
for i in [2..Length(arg)] do
if IsString(arg[i]) and Length(arg[i]) > 0 then
type := arg[i];
elif IsDenseList(arg[i]) and ForAll(arg[i], IsList) then
strings := arg[i];
elif IsRecord(arg[i]) then
opts := arg[i];
fi;
od;
if opts = fail then
opts := rec();
fi;
if type = fail or type = "default" then
type := "BibTeX";
if not IsBound(opts.useAlt) then
opts.useAlt := ["BibTeX", "LaTeX"];
fi;
fi;
if strings = fail then
strings := [];
fi;
res := BuildRecBibXMLEntry(entry, entry, type, strings, opts);
return res;
end);
## <#GAPDoc Label="StringBibXMLEntry">
##
##
## a string
##
## The arguments of this function have the same meaning as in but the return value is a string representing the
## bibliography entry in a format specified by restype (default is
## "BibTeX" ).
##
##
## Currently, the following cases for restype are supported:
##
## "BibTeX" - A string with &BibTeX; source code
## is generated.
## "Text"
## - A text representation of the text is returned. If
##
options.ansi is bound it must be a record. The components must have
## names Bib_Label , Bib_author , and so on for all fieldnames.
## The value of each component is a pair of strings which will enclose the
## content of the field in the result or the first of these strings in which
## case the default for the second is TextAttr.reset (see ). If you give an empty record here, some default ANSI color
## markup will be used.
## "HTML"
## - An HTML representation of the bibliography entry is returned. The text
## from each field is enclosed in markup (mostly
<span> -elements)
## with the class attribute set to the field name. This allows a
## detailed layout of the code via a style sheet file.
## If options.MathJax is bound and has the value true then
## formulae are encoded for display on pages with MathJax
## support.
##
##
## We use again the file shown in the example for .
##
## gap> bib := ParseBibXMLextFiles("doc/testbib.xml");;
## gap> e := bib.entries[1];; strs := bib.strings;;
## gap> ebib := StringBibXMLEntry(e, "BibTeX", strs);;
## gap> PrintFormattedString(ebib);
## @article{ AB2000,
## author = {First, F. A. and Sec{\H o}nd, X. Y.},
## title = {The {F}ritz package for the formula $x^y -
## l_{{i+1}} \rightarrow \mathbb{R}$},
## journal = {Important Journal},
## number = {13},
## year = {2000},
## pages = {13{\textendash}25},
## note = {Online data at \href
## {http://www.publish.com/~ImpJ/123#data} {Bla
## Bla Publisher}},
## mycomment = {very useful},
## printedkey = {FS00}
## }
## gap> etxt := StringBibXMLEntry(e, "Text", strs);;
## gap> etxt := SimplifiedUnicodeString(Unicode(etxt), "latin1", "single");;
## gap> etxt := Encode(etxt, GAPInfo.TermEncoding);;
## gap> PrintFormattedString(etxt);
## [FS00] First, F. A. and Second, X. Y., The Fritz package for the
## formula x^y - l_{i+1} ? R, Important Journal, 13 (2000), 13-25,
## (Online data at Bla Bla Publisher
## (http://www.publish.com/~ImpJ/123#data)).
## gap> ehtml := StringBibXMLEntry(e, "HTML", strs, rec(MathJax := true));;
## gap> ehtml := Encode(Unicode(ehtml), GAPInfo.TermEncoding);;
## gap> PrintFormattedString(ehtml);
##
## [FS00 ]
## First, F. A. and Secőnd, X. Y. ,
## The Fritz package for the
## formula \(x^y - l_{{i+1}} \rightarrow \mathbb{R}\) ,
## Important Journal
## (13 )
## (2000 ),
## 13–25
## (Online data at
## Bla Bla
## Publisher ).
##
## ]]>
##
##
##
## <#/GAPDoc>
InstallGlobalFunction(StringBibXMLEntry, function(arg)
local r, type, opts;
r := CallFuncList(RecBibXMLEntry, arg);
type := r.From.type;
opts := r.From.options;
if IsBound(STRINGBIBXMLHDLR.(type)) then
return STRINGBIBXMLHDLR.(type)(r);
else
InfoBibTools(1, "#W Don't know how to make a string of type ", type, "\n");
return fail;
fi;
end);
STRINGBIBXMLHDLR.BibTeX := StringBibAsBib;
STRINGBIBXMLHDLR.Text := StringBibAsText;
STRINGBIBXMLHDLR.HTML := StringBibAsHTML;
# Utility for a sort key, can be given as field 'sortkey' or element, respectively: as list of strings separated by ",".
# If not given we use list of last names of authors/editors (or the title)
# transformed to lower case.
InstallGlobalFunction(SortKeyRecBib, function(r)
local res;
res := [];
if IsBound(r.sortkey) then
Append(res, List(SplitString(r.sortkey, "", ","), NormalizedWhitespace));
fi;
if IsBound(r.authorAsList) then
Append(res, List(r.authorAsList, a-> LowerASCIIString(a[1])));
fi;
if IsBound(r.editorAsList) then
Append(res, List(r.editorAsList, a-> LowerASCIIString(a[1])));
fi;
if IsBound(r.year) then
Add(res, r.year);
fi;
if IsBound(r.title) then
Add(res, LowerASCIIString(NormalizedWhitespace(r.title)));
fi;
if Length(res) = 0 then
Add(res, "zzzzzzzzzz");
fi;
return res;
end);