our
%FMT_SPEC
;
our
@META_BLOCK
;
sub
new {
my
(
$class
,
%options
) =
@_
;
my
$self
=
$class
->SUPER::new(
%options
);
$$self
{
split
} =
$options
{
split
};
$$self
{bibliographies} =
$options
{bibliographies};
return
$self
; }
sub
toProcess {
my
(
$self
,
$doc
) =
@_
;
return
$doc
->findnodes(
'//ltx:bibliography'
); }
sub
process {
my
(
$self
,
$doc
,
@bibs
) =
@_
;
my
@docs
= (
$doc
);
foreach
my
$bib
(
@bibs
) {
next
if
$doc
->findnodes(
'.//ltx:bibitem'
,
$bib
);
local
$LaTeXML::Post::MakeBibliography::NUMBER
= 0;
local
%LaTeXML::Post::MakeBibliography::STYLE
=
(
map
{ (
$_
=>
$bib
->getAttribute(
$_
)) }
qw(bibstyle citestyle sort)
);
my
$entries
=
$self
->getBibEntries(
$doc
,
$bib
);
$doc
->removeNodes(
$doc
->findnodes(
'//ltx:bibentry'
));
foreach
my
$biblist
(
$doc
->findnodes(
'//ltx:biblist'
)) {
$doc
->removeNodes(
$biblist
)
unless
element_nodes(
$biblist
); }
if
(
$$self
{
split
}) {
my
$split
= {};
foreach
my
$sortkey
(
keys
%$entries
) {
my
$entry
=
$$entries
{
$sortkey
};
$$split
{
$$entry
{initial} }{
$sortkey
} =
$entry
; }
@docs
=
map
{
$self
->rescan(
$_
) }
$self
->makeSubCollectionDocuments(
$doc
,
$bib
,
map
{ (
$_
=>
$self
->makeBibliographyList(
$doc
,
$bib
,
$_
,
$$split
{
$_
})) }
sort
keys
%$split
); }
else
{
$doc
->addNodes(
$bib
,
$self
->makeBibliographyList(
$doc
,
$bib
,
undef
,
$entries
));
$self
->rescan(
$doc
); } }
return
@docs
; }
sub
getBibliographies {
my
(
$self
,
$doc
) =
@_
;
my
@bibnames
= ();
my
$fromBibliography
= 0;
if
(
$$self
{bibliographies} &&
scalar
(@{
$$self
{bibliographies} })) {
@bibnames
= @{
$$self
{bibliographies} }; }
else
{
my
$bibnode
=
$doc
->findnode(
'//ltx:bibliography'
);
if
(
my
$files
=
$bibnode
->getAttribute(
'files'
)
||
$bibnode
->parentNode->getAttribute(
'files'
)
) {
$fromBibliography
= 1;
@bibnames
=
split
(
','
,
$files
); } }
my
@paths
=
$doc
->getSearchPaths;
my
@bibs
= ();
my
@rawbibs
= ();
foreach
my
$bib
(
@bibnames
) {
my
$ref
=
ref
$bib
;
my
$bibdoc
;
if
(
$ref
&& (
$ref
eq
'LaTeXML::Post::Document'
)) {
$bibdoc
=
$bib
; }
elsif
(
$ref
&& (
$ref
eq
'XML::LibXML::Document'
)) {
$bibdoc
=
$doc
->new(
$bib
,
sourceDirectory
=>
'.'
); }
elsif
(
$ref
) {
Error(
'unexpected'
,
$ref
,
$self
,
"Don't know how to convert '$bib' (a '$ref') into a Bibliography document"
); }
elsif
(pathname_is_literaldata(
$bib
)) {
push
(
@rawbibs
,
$bib
);
next
; }
elsif
(
$bib
=~ /\.xml$/) {
$bibdoc
=
$doc
->newFromFile(
$bib
); }
elsif
(
$bib
=~ /\.bib(?:\.xml)?$/ ||
$fromBibliography
) {
my
$xmlbib
=
$bib
;
$xmlbib
.=
'.bib'
if
$fromBibliography
&& !(
$xmlbib
=~ /\.bib$/);
if
(
my
$xmlpath
= pathname_find(
$xmlbib
,
paths
=> [
@paths
],
types
=> [
'xml'
])) {
$bibdoc
=
$doc
->newFromFile(
$xmlpath
); }
elsif
(
my
$bibpath
= pathname_find(
$bib
,
paths
=> [
@paths
],
types
=> [
'bib'
])
|| pathname_kpsewhich(
$bib
)) {
push
(
@rawbibs
,
$bibpath
);
next
; }
else
{
Error(
'missing_file'
,
$bib
,
$self
,
"Couldn't find Bibliography '$bib'"
,
"Searchpaths were "
.
join
(
','
,
@paths
)); } }
if
(
$bibdoc
) {
push
(
@bibs
,
$bibdoc
); }
else
{
Info(
'expected'
,
$bib
,
$self
,
"Couldn't find usable Bibliography for '$bib'"
); } }
if
(
@rawbibs
) {
my
$raw
;
if
(
scalar
(
@rawbibs
) == 1) {
$raw
=
$rawbibs
[0]; }
else
{
$raw
=
'literal:'
;
for
my
$rawbib
(
@rawbibs
) {
if
(
$rawbib
=~ s/literal\://) {
$raw
.=
$rawbib
; }
else
{
if
(
open
(
my
$bibfh
,
'<'
,
$rawbib
)) {
$raw
.=
join
(
""
, <
$bibfh
>);
close
$bibfh
; }
else
{
Info(
"open"
,
$rawbib
,
$self
,
"Couldn't open file $rawbib"
); } }
$raw
.=
"%\n"
; } }
my
$bibdoc
=
$self
->convertBibliography(
$doc
,
$raw
);
push
(
@bibs
,
$bibdoc
)
if
$bibdoc
; }
NoteLog(
"MakeBibliography: using bibliographies "
.
join
(
','
,
map
{ (
length
(
$_
) > 100 ?
substr
(
$_
, 100) .
'...'
:
$_
) }
@bibnames
)
.
"]"
);
return
@bibs
; }
sub
convertBibliography {
my
(
$self
,
$doc
,
$bib
) =
@_
;
my
@preload
= ();
my
(
$classdata
,
@packages
) =
$self
->find_documentclass_and_packages(
$doc
);
my
(
$class
,
$classoptions
) =
@$classdata
;
if
(
$class
) {
if
(
$classoptions
) {
push
(
@preload
,
"[$classoptions]$class.cls"
); }
else
{
push
(
@preload
,
"$class.cls"
); } }
foreach
my
$po
(
@packages
) {
my
(
$pkg
,
$options
) =
@$po
;
if
(
$options
) {
push
(
@preload
,
"[$options]$pkg.sty"
); }
else
{
push
(
@preload
,
"$pkg.sty"
); } }
my
$bibname
= pathname_is_literaldata(
$bib
) ?
'Anonymous Bib String'
:
$bib
;
my
$stage
=
"Recursive MakeBibliography $bibname"
;
ProgressSpinup(
$stage
);
my
$bib_config
= LaTeXML::Common::Config->new(
recursive
=> 1,
cache_key
=>
'BibTeX'
,
type
=>
"BibTeX"
,
post
=> 0,
format
=>
'dom'
,
whatsin
=>
'document'
,
whatsout
=>
'document'
,
includestyles
=> 1,
bibliographies
=> [],
paths
=>
$$doc
{searchpaths},
(
@preload
? (
preload
=> [
@preload
]) : ()));
my
$bib_converter
= LaTeXML->get_converter(
$bib_config
);
my
$biblog
=
''
;
$bib_converter
->prepare_session(
$bib_config
);
my
$response
=
$bib_converter
->convert(
$bib
);
MergeStatus(
$$bib_converter
{latexml}{state});
ProgressSpindown(
$stage
);
if
(
my
$bibdoc
=
$$response
{result}) {
return
$doc
->new(
$bibdoc
,
sourceDirectory
=>
'.'
); }
return
; }
sub
getBibEntries {
my
(
$self
,
$doc
,
$bib
) =
@_
;
my
%entries
= ();
foreach
my
$bibdoc
(
$self
->getBibliographies(
$doc
)) {
my
@lists
=
split
(/\s+/,
$doc
->findnode(
'//ltx:bibliography'
)->getAttribute(
'lists'
) ||
'bibliography'
);
foreach
my
$bibentry
(
$bibdoc
->findnodes(
'//ltx:bibentry'
)) {
my
$bibkey
=
$bibentry
->getAttribute(
'key'
);
my
$lcbibkey
=
lc
(
$bibkey
);
my
$bibid
=
$bibentry
->getAttribute(
'xml:id'
);
$entries
{
$lcbibkey
}{bibkey} =
$bibkey
;
$entries
{
$lcbibkey
}{bibentry} =
$bibentry
;
$entries
{
$lcbibkey
}{citations} = [
grep
{
$_
}
map
{
split
(
','
,
$_
->value) }
$bibdoc
->findnodes(
'.//@bibrefs'
,
$bibentry
)]; } }
my
@lists
=
split
(/\s+/,
$bib
->getAttribute(
'lists'
) ||
'bibliography'
);
my
$citestar
=
grep
{
$$self
{db}->lookup(
"BIBLABEL:$_:*"
); }
@lists
;
my
@queue
= ();
foreach
my
$dbkey
(
$$self
{db}->getKeys) {
if
(
$dbkey
=~ /^BIBLABEL:(.*?):(.*)$/) {
my
(
$list
,
$bibkey
) = ($1, $2);
next
unless
grep
{
$_
eq
$list
; }
@lists
;
my
$lcbibkey
=
lc
(
$bibkey
);
my
$bibdbentry
=
$$self
{db}->lookup(
$dbkey
);
if
(
my
$referrers
=
$bibdbentry
->getValue(
'referrers'
)) {
foreach
my
$refr
(
keys
%$referrers
) {
my
(
$rid
,
$e
,
$t
) = (
$refr
,
undef
,
undef
);
while
(
$rid
&& (
$e
=
$$self
{db}->lookup(
"ID:$rid"
)) && ((
$t
= (
$e
->getValue(
'type'
) ||
''
)) ne
'ltx:bibitem'
)) {
$rid
=
$e
->getValue(
'parent'
); }
if
(!
$e
) {
Warn(
'expected'
,
'entry'
,
undef
,
"Didn't find an entry for reference id=$rid"
); }
elsif
(
$t
ne
'ltx:bibitem'
) {
if
(
my
$prevkey
=
$entries
{
$lcbibkey
}{citedkey}) {
Warn(
'unexpected'
,
'bibkey'
,
undef
,
"Case mismatch in bib key '$prevkey' vs '$bibkey'"
)
if
$prevkey
ne
$bibkey
; }
$entries
{
$lcbibkey
}{citedkey} =
$bibkey
;
$entries
{
$lcbibkey
}{referrers}{
$refr
} = 1; } }
push
(
@queue
,
$bibkey
)
if
keys
%{
$entries
{
$lcbibkey
}{referrers} }; }
elsif
(
$citestar
) {
push
(
@queue
,
$bibkey
); } } }
my
%seen_keys
= ();
my
%missing_keys
= ();
my
$included
= {};
while
(
my
$bibkey
=
shift
(
@queue
)) {
next
if
$seen_keys
{
$bibkey
};
$seen_keys
{
$bibkey
} = 1;
next
if
$bibkey
eq
'*'
;
my
$lcbibkey
=
lc
(
$bibkey
);
if
(
my
$bibentry
=
$entries
{
$lcbibkey
}{bibentry}) {
my
$entry
=
$entries
{
$lcbibkey
};
my
$names
=
''
;
my
$sortnames
=
''
;
my
@names
=
$doc
->findnodes(
'ltx:bib-name[@role="author"]'
,
$bibentry
);
@names
=
$doc
->findnodes(
'ltx:bib-name[@role="editor"]'
,
$bibentry
)
unless
@names
;
if
(
my
$n
=
$doc
->findnode(
'ltx:bib-key'
,
$bibentry
)) {
$sortnames
=
$names
=
$n
->textContent; }
elsif
(
scalar
(
@names
)) {
$sortnames
=
join
(
' '
,
map
{ getNameText(
$doc
,
$_
) }
@names
);
my
@ns
=
map
{
$_
&&
$_
->textContent }
map
{
$doc
->findnodes(
'ltx:surname'
,
$_
) }
@names
;
if
(
@ns
> 2) {
$names
=
$ns
[0] .
' et al'
; }
elsif
(
@ns
> 1) {
$names
=
$ns
[0] .
' and '
.
$ns
[1]; }
else
{
$names
=
$ns
[0]; } }
elsif
(
my
$t
=
$doc
->findnode(
'ltx:bib-title'
,
$bibentry
)) {
$sortnames
=
$names
=
$t
->textContent; }
my
$date
=
$doc
->findnode(
'ltx:bib-date[@role="publication"] | ltx:bib-type'
,
$bibentry
);
my
$title
=
$doc
->findnode(
'ltx:bib-title'
,
$bibentry
);
$date
= (
$date
?
$date
->textContent :
''
);
$date
= $1
if
$date
&&
$date
=~ /^(\d\d\d\d)/;
$title
= (
$title
?
$title
->textContent :
''
);
$$entry
{ay} =
"$names.$date"
;
$$entry
{initial} =
$doc
->initial(
$names
, 1);
$$included
{
lc
(
join
(
'.'
,
$sortnames
,
$date
,
$title
,
$bibkey
)) } =
$entry
;
push
(
@queue
, @{
$$entry
{citations} })
if
$$entry
{citations}; }
else
{
$missing_keys
{
$bibkey
} = 1; } }
foreach
my
$sortkey
(
keys
%$included
) {
my
$entry
=
$$included
{
$sortkey
};
my
$bibkey
=
$$entry
{bibkey};
map
{
$entries
{
lc
(
$_
) }{bibreferrers}{
$bibkey
} = 1 } @{
$$entry
{citations} }; }
NoteLog(
"MakeBibliography: "
. (
scalar
keys
%entries
) .
" bibentries, "
. (
scalar
keys
%$included
) .
" cited"
);
Warn(
'expected'
,
'bibkeys'
,
undef
,
"Missing bibkeys "
.
join
(
', '
,
sort
keys
%missing_keys
))
if
keys
%missing_keys
;
my
@sortkeys
=
$doc
->unisort(
keys
%$included
);
my
%suffixes
= ();
while
(
my
$sortkey
=
shift
(
@sortkeys
)) {
my
$entry
=
$$included
{
$sortkey
};
my
$ay
=
$$entry
{ay};
if
(
defined
$suffixes
{
$ay
}) {
my
$prev
=
$suffixes
{
$ay
};
if
(!
$$prev
{suffix}) {
$$prev
{suffix_counter} = 1;
$$prev
{suffix} = radix_alpha(
$$prev
{suffix_counter}); }
$$entry
{suffix_counter} =
$$prev
{suffix_counter} + 1;
$$entry
{suffix} = radix_alpha(
$$entry
{suffix_counter}); }
$suffixes
{
$ay
} =
$entry
;
foreach
my
$sortnode
(
$doc
->findnodes(
'//ltx:ERROR[@class="sort"]'
,
$$entry
{bibentry})) {
$sortnode
->parentNode->removeChild(
$sortnode
); }
}
return
$included
; }
sub
getNameText {
my
(
$doc
,
$namenode
) =
@_
;
my
$surname
=
$doc
->findnodes(
'ltx:surname'
,
$namenode
);
my
$givenname
=
$doc
->findnodes(
'ltx:givenname'
,
$namenode
);
return
(
$surname
&&
$givenname
?
$surname
.
' '
.
$givenname
:
$surname
||
$givenname
); }
sub
makeBibliographyList {
my
(
$self
,
$doc
,
$bib
,
$initial
,
$entries
) =
@_
;
my
$id
=
$bib
->getAttribute(
'xml:id'
)
||
$doc
->getDocumentElement->getAttribute(
'xml:id'
) ||
'bib'
;
$id
.=
".L1"
;
$id
.=
".$initial"
if
$initial
;
return
[
'ltx:biblist'
, {
'xml:id'
=>
$id
},
map
{
$self
->formatBibEntry(
$doc
,
$bib
,
$$entries
{
$_
}) }
$doc
->unisort(
keys
%$entries
)]; }
sub
formatBibEntry {
my
(
$self
,
$doc
,
$bib
,
$entry
) =
@_
;
my
$bibentry
=
$$entry
{bibentry};
my
$citedkey
=
$$entry
{citedkey} ||
$$entry
{bibkey};
my
$id
=
$bibentry
->getAttribute(
'xml:id'
);
my
$key
=
$bibentry
->getAttribute(
'key'
);
my
$type
=
$bibentry
->getAttribute(
'type'
);
my
@blockspecs
= @{
$FMT_SPEC
{
$type
} || [] };
if
(
my
$bibid
=
$bib
->getAttribute(
'xml:id'
)
||
$doc
->getDocumentElement->getAttribute(
'xml:id'
) ||
'bib'
) {
$id
=~ s/^bib//;
$id
=
$bibid
.
$id
; }
local
$LaTeXML::Post::MakeBibliography::SUFFIX
=
$$entry
{suffix};
my
$number
= ++
$LaTeXML::Post::MakeBibliography::NUMBER
;
Warn(
'unexpected'
,
$type
,
undef
,
"No formatting specification for bibentry of type '$type'"
)
unless
@blockspecs
;
my
@tags
= ();
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'number'
,
class
=>
'ltx_bib_number'
},
$number
]);
my
@names
=
$doc
->findnodes(
'ltx:bib-name[@role="author"]/ltx:surname'
,
$bibentry
);
@names
=
$doc
->findnodes(
'ltx:bib-name[@role="editor"]/ltx:surname'
,
$bibentry
)
unless
@names
;
my
$etal
= 0;
if
(
@names
&& (
$names
[-1]->toString eq
'others'
)) {
$etal
= 1; }
if
(
@names
> 2) {
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'authors'
,
class
=>
'ltx_bib_author'
},
$doc
->cloneNodes(
$names
[0]->childNodes),
[
'ltx:text'
, {
class
=>
'ltx_bib_etal'
},
' et al.'
]]);
my
@fnames
= ();
foreach
my
$n
(
@names
[0 ..
$#names
- 1]) {
push
(
@fnames
,
$n
->childNodes,
', '
); }
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'fullauthors'
,
class
=>
'ltx_bib_author'
},
$doc
->cloneNodes(
@fnames
),
' and '
,
$doc
->cloneNodes(
$names
[-1]->childNodes)]); }
elsif
(
@names
> 1) {
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'authors'
,
class
=>
'ltx_bib_author'
},
$doc
->cloneNodes(
$names
[0]->childNodes),
' and '
,
$doc
->cloneNodes(
$names
[1]->childNodes)]); }
elsif
(
@names
) {
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'authors'
,
class
=>
'ltx_bib_author'
},
$doc
->cloneNodes(
$names
[0]->childNodes)]); }
my
$keytag
;
if
(
$keytag
=
$doc
->findnode(
'ltx:bib-key'
,
$bibentry
)) {
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'key'
,
class
=>
'ltx_bib_key'
},
$doc
->cloneNodes(
$keytag
->childNodes)]); }
my
@year
= ();
if
(
my
$date
=
$doc
->findnode(
'ltx:bib-date[@role="publication"]'
,
$bibentry
)) {
@year
=
$date
->childNodes;
if
(
my
$datetext
=
$date
->textContent) {
if
(
$datetext
=~ /^(\d\d\d\d)/) {
@year
= ($1); } }
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'year'
,
class
=>
'ltx_bib_year'
},
$doc
->cloneNodes(
@year
), (
$$entry
{suffix} ||
''
)]); }
my
$typetag
;
if
(
$typetag
=
$doc
->findnode(
'ltx:bib-type'
,
$bibentry
)) {
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'bibtype'
,
class
=>
'ltx_bib_type'
},
$doc
->cloneNodes(
$typetag
->childNodes)]); }
if
(
my
$title
=
$doc
->findnode(
'ltx:bib-title'
,
$bibentry
)) {
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'title'
,
class
=>
'ltx_bib_title'
},
$doc
->cloneNodes(
$title
->childNodes)]); }
my
$style
=
$LaTeXML::Post::MakeBibliography::STYLE
{citestyle} ||
'numbers'
;
$style
=
'numbers'
unless
(
@names
||
$keytag
) && (
@year
||
$typetag
);
if
(
$style
eq
'numbers'
) {
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'refnum'
,
class
=>
'ltx_bib_key'
,
open
=>
'['
,
close
=>
']'
},
$number
]); }
elsif
(
$style
eq
'AY'
) {
my
@rfnames
;
if
(
my
@authors
=
$doc
->findnodes(
'ltx:bib-name[@role="author"]/ltx:surname'
,
$bibentry
)) {
@rfnames
=
@authors
; }
elsif
(
my
@editors
=
$doc
->findnodes(
'ltx:bib-name[@role="editor"]/ltx:surname'
,
$bibentry
)) {
@rfnames
=
@editors
; }
else
{
@rfnames
=
$keytag
->childNodes; }
my
$aa
;
if
(
scalar
(
@rfnames
) > 1) {
$aa
=
join
(
''
,
map
{
substr
(
$_
->textContent, 0, 1); }
@rfnames
);
if
(
length
(
$aa
) > 3) {
$aa
=
substr
(
$aa
, 0, 3) .
"+"
; } }
else
{
$aa
=
uc
(
substr
(
$rfnames
[0]->textContent, 0, 3)); }
my
$yrtext
= (
@year
?
join
(
''
,
map
{ (
ref
$_
?
$_
->textContent :
$_
); }
@year
) :
''
);
my
$yy
= (
length
(
$yrtext
) >= 2 ?
substr
(
$yrtext
, 2, 2) :
$yrtext
);
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'refnum'
,
class
=>
'ltx_bib_abbrv'
,
open
=>
'['
,
close
=>
']'
},
$aa
.
$yy
. (
$$entry
{suffix} ||
''
)]); }
else
{
shift
(
@blockspecs
);
my
@rfnames
;
if
(
my
@authors
=
$doc
->findnodes(
'ltx:bib-name[@role="author"]'
,
$bibentry
)) {
@rfnames
= do_authors(
@authors
); }
elsif
(
my
@editors
=
$doc
->findnodes(
'ltx:bib-name[@role="editor"]'
,
$bibentry
)) {
@rfnames
= do_editorsA(
@editors
); }
else
{
@rfnames
=
$keytag
->childNodes; }
my
@rfyear
= (
@year
? (
@year
, (
$$entry
{suffix} ||
''
))
: (
$typetag
?
$typetag
->childNodes : ()));
push
(
@tags
, [
'ltx:tag'
, {
role
=>
'refnum'
,
class
=>
'ltx_bib_author-year'
},
$doc
->cloneNodes(
@rfnames
),
' ('
,
$doc
->cloneNodes(
@rfyear
),
')'
]); }
my
@blocks
= ();
foreach
my
$blockspec
(
@blockspecs
) {
my
@x
= ();
foreach
my
$row
(
@$blockspec
) {
my
(
$xpath
,
$punct
,
$pre
,
$class
,
$op
,
$post
) =
@$row
;
my
$negated
=
$xpath
=~ s/^!\s*//;
my
@nodes
= (
$xpath
eq
'true'
? () :
$doc
->findnodes(
$xpath
,
$bibentry
));
next
if
(
$xpath
ne
'true'
) && (
$negated
?
@nodes
: !
@nodes
);
push
(
@x
,
$punct
)
if
$punct
&&
@x
;
push
(
@x
,
$pre
)
if
$pre
;
push
(
@x
, [
'ltx:text'
, {
class
=>
'ltx_bib_'
.
$class
},
&$op
(
$doc
->cloneNodes(
@nodes
))])
if
$op
;
push
(
@x
,
$post
)
if
$post
; }
push
(
@blocks
, [
'ltx:bibblock'
, {
'xml:space'
=>
'preserve'
},
@x
])
if
@x
;
}
my
@citedby
=
map
{ [
'ltx:ref'
, {
idref
=>
$_
,
show
=>
'typerefnum'
}] }
sort
keys
%{
$$entry
{referrers} };
push
(
@citedby
, [
'ltx:bibref'
, {
bibrefs
=>
join
(
','
,
sort
keys
%{
$$entry
{bibreferrers} }),
show
=>
'refnum'
}])
if
$$entry
{bibreferrers};
push
(
@blocks
, [
'ltx:bibblock'
, {
class
=>
'ltx_bib_cited'
},
"Cited by: "
,
$doc
->conjoin(
",\n"
,
@citedby
),
'.'
])
if
@citedby
;
return
[
'ltx:bibitem'
, {
'xml:id'
=>
$id
,
key
=>
$citedkey
,
type
=>
$type
,
class
=>
"ltx_bib_$type"
},
(
@tags
? ([
'ltx:tags'
, {},
@tags
]) : ()),
@blocks
]; }
sub
do_any {
my
(
@stuff
) =
@_
;
return
@stuff
; }
sub
do_name {
my
(
$node
) =
@_
;
my
$first
=
$LaTeXML::Post::DOCUMENT
->findnode(
'ltx:givenname'
,
$node
);
if
(
$first
) {
$first
=
join
(
''
,
map
{ (/\.$/ ?
"$_ "
: (/^(.)/ ?
"$1. "
:
''
)) }
split
(/\s/,
$first
->textContent)); }
else
{
$first
= (); }
my
$sur
=
$LaTeXML::Post::DOCUMENT
->findnode(
'ltx:surname'
,
$node
);
return
(
$first
,
$sur
->cloneNode(1)->childNodes); }
sub
do_names {
my
(
@names
) =
@_
;
my
@stuff
= ();
my
$sep
= (
scalar
(
@names
) > 2 ?
', '
:
' '
);
my
$etal
= 0;
if
(
@names
&& (
$names
[-1]->textContent eq
'others'
)) {
pop
(
@names
);
$etal
= 1; }
my
$n
=
scalar
(
@names
);
while
(
my
$name
=
shift
(
@names
)) {
if
(
@stuff
) {
push
(
@stuff
,
$sep
);
push
(
@stuff
,
'and '
)
if
!
$etal
&& !
@names
; }
push
(
@stuff
, do_name(
$name
)); }
if
(
$etal
) {
push
(
@stuff
,
$sep
, [
'ltx:text'
, {
class
=>
'ltx_bib_etal'
},
'et al.'
]); }
return
@stuff
; }
sub
do_names_short {
my
(
@names
) =
@_
;
if
(
@names
> 2) {
return
(
$names
[0]->childNodes,
' '
, [
'ltx:text'
, {
class
=>
'ltx_bib_etal'
},
'et al.'
]); }
elsif
(
@names
> 1) {
return
(
$names
[0]->childNodes,
' and '
,
$names
[1]->childNodes); }
elsif
(
@names
) {
return
(
$names
[0]->childNodes); } }
sub
do_authors {
my
(
@stuff
) =
@_
;
return
do_names(
@stuff
); }
sub
do_editorsA {
my
(
@stuff
) =
@_
;
my
@n
= do_names(
@stuff
);
if
(
scalar
(
@stuff
) > 1) {
push
(
@n
,
" (Eds.)"
); }
elsif
(
scalar
(
@stuff
)) {
push
(
@n
,
" (Ed.)"
); }
return
@n
; }
sub
do_editorsB {
my
(
@stuff
) =
@_
;
my
@x
= do_names(
@stuff
);
if
(
scalar
(
@stuff
) > 1) {
push
(
@x
,
" Eds."
); }
elsif
(
scalar
(
@stuff
)) {
push
(
@x
,
" Ed."
); }
return
(
@x
? (
"("
,
@x
,
")"
) : ()); }
sub
do_year {
my
(
@stuff
) =
@_
;
return
(
' ('
,
@stuff
,
@LaTeXML::Post::MakeBibliography::SUFFIX
,
')'
); }
sub
do_type {
my
(
@stuff
) =
@_
;
return
(
'('
,
@stuff
,
')'
); }
sub
do_title {
my
(
@stuff
) =
@_
;
return
(
@stuff
); }
sub
do_edition {
my
(
@stuff
) =
@_
;
return
(
@stuff
,
" edition"
); }
sub
do_thesis_type {
my
(
@stuff
) =
@_
;
return
@stuff
; }
sub
do_pages {
my
(
@stuff
) =
@_
;
return
(
" pp."
.
pack
(
'U'
, 0xA0),
@stuff
); }
sub
do_crossref {
my
(
$node
,
@stuff
) =
@_
;
return
([
'ltx:cite'
, {},
[
'ltx:bibref'
, {
bibrefs
=>
$node
->getAttribute(
'bibrefs'
),
show
=>
'title, author'
}]]); }
my
$LINKS
=
"ltx:bib-links | ltx:bib-review | ltx:bib-identifier | ltx:bib-url"
;
sub
do_links {
my
(
@nodes
) =
@_
;
my
@links
= ();
my
$doc
=
$LaTeXML::Post::DOCUMENT
;
foreach
my
$node
(
@nodes
) {
my
$scheme
=
$node
->getAttribute(
'scheme'
) ||
''
;
my
$href
=
$node
->getAttribute(
'href'
);
my
$tag
=
$doc
->getQName(
$node
);
if
((
$tag
eq
'ltx:bib-identifier'
) || (
$tag
eq
'ltx:bib-review'
)) {
if
(
$href
) {
push
(
@links
, [
'ltx:ref'
, {
href
=>
$href
,
class
=>
"$scheme ltx_bib_external"
},
$doc
->cloneNodes(
$node
->childNodes)]); }
else
{
push
(
@links
, [
'ltx:text'
, {
class
=>
"$scheme ltx_bib_external"
},
$doc
->cloneNodes(
$node
->childNodes)]); } }
elsif
(
$tag
eq
'ltx:bib-links'
) {
push
(
@links
, [
'ltx:text'
, {
class
=>
"ltx_bib_external"
},
$doc
->cloneNodes(
$node
->childNodes)]); }
elsif
(
$tag
eq
'ltx:bib-url'
) {
push
(
@links
, [
'ltx:ref'
, {
href
=>
$href
,
class
=>
'ltx_bib_external'
},
$doc
->cloneNodes(
$node
->childNodes)]); } }
@links
=
map
{ (
",\n"
,
$_
) }
@links
;
return
@links
[1 ..
$#links
]; }
@META_BLOCK
=
([[
'ltx:bib-note'
,
''
,
"Note: "
,
'note'
, \
&do_any
,
''
]],
[[
$LINKS
,
''
,
'External Links: '
,
'links'
, \
&do_links
,
''
]]);
%FMT_SPEC
=
(
article
=>
[[[
'ltx:bib-name[@role="author"]'
,
''
,
''
,
'author'
, \
&do_authors
,
''
],
[
'ltx:bib-date[@role="publication"]'
,
''
,
''
,
'year'
, \
&do_year
,
''
]],
[[
'ltx:bib-title'
,
''
,
''
,
'title'
, \
&do_title
,
'.'
]],
[[
'ltx:bib-part[@role="part"]'
,
''
,
''
,
'part'
, \
&do_any
,
''
],
[
'ltx:bib-related/ltx:bib-title'
,
', '
,
''
,
'journal'
, \
&do_any
,
''
],
[
'ltx:bib-part[@role="volume"]'
,
' '
,
''
,
'volume'
, \
&do_any
,
''
],
[
'ltx:bib-part[@role="number"]'
,
' '
,
'('
,
'number'
, \
&do_any
,
')'
],
[
'ltx:bib-status'
,
', '
,
'('
,
'status'
, \
&do_any
,
')'
],
[
'ltx:bib-part[@role="pages"]'
,
', '
,
''
,
'pages'
, \
&do_pages
,
''
],
[
'ltx:bib-language'
,
' '
,
'('
,
'language'
, \
&do_any
,
')'
],
[
'true'
,
'.'
]],
@META_BLOCK
],
book
=>
[[[
'ltx:bib-name[@role="author"]'
,
''
,
''
,
'author'
, \
&do_authors
,
''
],
[
'ltx:bib-name[@role="editor"]'
,
''
,
''
,
'editor'
, \
&do_editorsA
,
''
],
[
'ltx:bib-date[@role="publication"]'
,
''
,
''
,
'year'
, \
&do_year
,
''
]],
[[
'ltx:bib-title'
,
''
,
''
,
'title'
, \
&do_title
,
'.'
]],
[[
'ltx:bib-type'
,
''
,
''
,
'type'
, \
&do_any
,
''
],
[
'ltx:bib-edition'
,
', '
,
''
,
'edition'
, \
&do_edition
,
''
],
[
'ltx:bib-part[@role="series"]'
,
', '
,
''
,
'series'
, \
&do_any
,
''
],
[
'ltx:bib-part[@role="volume"]'
,
', '
,
'Vol. '
,
'volume'
, \
&do_any
,
''
],
[
'ltx:bib-part[@role="part"]'
,
', '
,
'Part '
,
'part'
, \
&do_any
,
''
],
[
'ltx:bib-publisher'
,
', '
,
' '
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-organization'
,
', '
,
' '
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-place'
,
', '
,
''
,
'place'
, \
&do_any
,
''
],
[
'ltx:bib-status'
,
' '
,
'('
,
'status'
, \
&do_any
,
')'
],
[
'ltx:bib-language'
,
' '
,
'('
,
'language'
, \
&do_any
,
')'
],
[
'true'
,
'.'
]],
@META_BLOCK
],
'incollection'
=>
[[[
'ltx:bib-name[@role="author"]'
,
''
,
''
,
'author'
, \
&do_authors
,
''
],
[
'ltx:bib-date[@role="publication"]'
,
''
,
''
,
'year'
, \
&do_year
,
''
]],
[[
'ltx:bib-title'
,
''
,
''
,
'title'
, \
&do_title
,
'.'
]],
[[
'ltx:bib-type'
,
''
,
''
,
'type'
, \
&do_any
,
''
],
[
'ltx:bib-related[@bibrefs]'
,
' '
,
'See '
,
'crossref'
, \
&do_crossref
,
','
],
[
'ltx:bib-related[@type][not(../ltx:bib-related[@bibrefs])]/ltx:bib-title'
,
' '
,
'In '
,
'inbook'
, \
&do_title
,
','
],
[
'ltx:bib-related[@type][not(../ltx:bib-related[@bibrefs])]/ltx:bib-name[@role="editor"]'
,
' '
,
' '
,
'editor'
, \
&do_editorsA
,
','
],
],
[[
'ltx:bib-edition'
,
''
,
''
,
'edition'
, \
&do_edition
,
''
],
[
'ltx:bib-name[@role="editor"]'
,
', '
,
''
,
'editor'
, \
&do_editorsB
,
''
],
[
'ltx:bib-related/ltx:bib-part[@role="series"]'
,
', '
,
''
,
'series'
, \
&do_any
,
''
],
[
'ltx:bib-related/ltx:bib-part[@role="volume"]'
,
', '
,
'Vol. '
,
'volume'
, \
&do_any
,
''
],
[
'ltx:bib-related/ltx:bib-part[@role="part"]'
,
', '
,
'Part '
,
'part'
, \
&do_any
,
''
],
[
'ltx:bib-publisher'
,
', '
,
' '
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-organization'
,
', '
,
''
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-place'
,
', '
,
''
,
'place'
, \
&do_any
,
''
],
[
'ltx:bib-part[@role="pages"]'
,
', '
,
''
,
'pages'
, \
&do_pages
,
''
],
[
'ltx:bib-status'
,
' '
,
'('
,
'status'
, \
&do_any
,
')'
],
[
'ltx:bib-language'
,
' '
,
'('
,
'language'
, \
&do_any
,
')'
],
[
'true'
,
'.'
]],
@META_BLOCK
],
report
=>
[[[
'ltx:bib-name[@role="author"]'
,
''
,
''
,
'author'
, \
&do_authors
,
''
],
[
'ltx:bib-name[@role="editor"]'
,
''
,
''
,
'editor'
, \
&do_editorsA
,
''
],
[
'ltx:bib-date[@role="publication"]'
,
''
,
''
,
'year'
, \
&do_year
,
''
]],
[[
'ltx:bib-title'
,
''
,
''
,
'title'
, \
&do_title
,
'.'
]],
[[
'ltx:bib-type'
,
''
,
''
,
'type'
, \
&do_any
,
''
]],
[[
'ltx:bib-part[@role="number"]'
,
''
,
'Technical Report '
,
'number'
, \
&do_any
,
''
],
[
'ltx:bib-part[@role="series"]'
,
', '
,
''
,
'series'
, \
&do_any
,
''
],
[
'ltx:bib-part[@role="volume"]'
,
', '
,
'Vol. '
,
'volume'
, \
&do_any
,
''
],
[
'ltx:bib-part[@role="part"]'
,
', '
,
'Part '
,
'part'
, \
&do_any
,
''
],
[
'ltx:bib-publisher'
,
', '
,
' '
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-organization'
,
', '
,
' '
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-place'
,
', '
,
' '
,
'place'
, \
&do_any
,
''
],
[
'ltx:bib-status'
,
', '
,
'('
,
'status'
, \
&do_any
,
')'
],
[
'ltx:bib-language'
,
' '
,
'('
,
'language'
, \
&do_any
,
')'
],
[
'true'
,
'.'
]],
@META_BLOCK
],
thesis
=>
[[[
'ltx:bib-name[@role="author"]'
,
''
,
''
,
'author'
, \
&do_authors
,
''
],
[
'ltx:bib-name[@role="editor"]'
,
''
,
''
,
'editor'
, \
&do_editorsA
,
''
],
[
'ltx:bib-date[@role="publication"]'
,
''
,
''
,
'year'
, \
&do_year
,
''
]],
[[
'ltx:bib-title'
,
''
,
''
,
'title'
, \
&do_title
,
'.'
]],
[[
'ltx:bib-type'
,
' '
,
''
,
'type'
, \
&do_thesis_type
,
''
],
[
'ltx:bib-part[@role="part"]'
,
', '
,
'Part '
,
'part'
, \
&do_any
,
''
],
[
'ltx:bib-publisher'
,
', '
,
''
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-organization'
,
', '
,
''
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-place'
,
', '
,
''
,
'place'
, \
&do_any
,
''
],
[
'ltx:bib-status'
,
', '
,
'('
,
'status'
, \
&do_any
,
')'
],
[
'ltx:bib-language'
,
', '
,
'('
,
'language'
, \
&do_any
,
')'
],
[
'true'
,
'.'
]],
@META_BLOCK
],
website
=>
[[[
'ltx:bib-name[@role="author"]'
,
''
,
''
,
'author'
, \
&do_authors
,
''
],
[
'ltx:bib-name[@role="editor"]'
,
''
,
''
,
'editor'
, \
&do_editorsA
,
''
],
[
'ltx:bib-date[@role="publication"]'
,
''
,
''
,
'year'
, \
&do_year
,
''
],
[
'ltx:bib-title'
,
''
,
''
,
'title'
, \
&do_any
,
''
],
[
'ltx:bib-type'
,
''
,
''
,
'type'
, \
&do_any
,
''
],
[
'! ltx:bib-type'
,
''
,
''
,
'type'
,
sub
{ (
'(Website)'
); },
''
]],
[[
'ltx:bib-organization'
,
', '
,
' '
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-place'
,
', '
,
''
,
'place'
, \
&do_any
,
''
],
[
'true'
,
'.'
]],
@META_BLOCK
],
software
=>
[[[
'ltx:bib-key'
,
''
,
''
,
'key'
, \
&do_any
,
''
],
[
'ltx:bib-type'
,
''
,
''
,
'type'
, \
&do_type
,
''
]],
[[
'ltx:bib-title'
,
''
,
''
,
'title'
, \
&do_any
,
''
]],
[[
'ltx:bib-organization'
,
', '
,
' '
,
'publisher'
, \
&do_any
,
''
],
[
'ltx:bib-place'
,
', '
,
''
,
'place'
, \
&do_any
,
''
],
[
'true'
,
'.'
]],
@META_BLOCK
],
);
$FMT_SPEC
{periodical} =
$FMT_SPEC
{book};
$FMT_SPEC
{collection} =
$FMT_SPEC
{book};
$FMT_SPEC
{proceedings} =
$FMT_SPEC
{book};
$FMT_SPEC
{manual} =
$FMT_SPEC
{book};
$FMT_SPEC
{misc} =
$FMT_SPEC
{book};
$FMT_SPEC
{unpublished} =
$FMT_SPEC
{book};
$FMT_SPEC
{booklet} =
$FMT_SPEC
{book};
$FMT_SPEC
{
'collection.article'
} =
$FMT_SPEC
{incollection};
$FMT_SPEC
{
'proceedings.article'
} =
$FMT_SPEC
{incollection};
$FMT_SPEC
{inproceedings} =
$FMT_SPEC
{incollection};
$FMT_SPEC
{inbook} =
$FMT_SPEC
{incollection};
$FMT_SPEC
{techreport} =
$FMT_SPEC
{report};
1;