texlive[76194] trunk: crossrefware (31aug25)

commits+karl at tug.org commits+karl at tug.org
Sun Aug 31 21:20:16 CEST 2025


Revision: 76194
          https://tug.org/svn/texlive?view=revision&revision=76194
Author:   karl
Date:     2025-08-31 21:20:16 +0200 (Sun, 31 Aug 2025)
Log Message:
-----------
crossrefware (31aug25)

Modified Paths:
--------------
    trunk/Build/source/texk/texlive/linked_scripts/crossrefware/bibzbladd.pl
    trunk/Build/source/texk/texlive/linked_scripts/crossrefware/ltx2crossrefxml.pl
    trunk/Master/texmf-dist/doc/man/man1/bibzbladd.1
    trunk/Master/texmf-dist/doc/man/man1/bibzbladd.man1.pdf
    trunk/Master/texmf-dist/doc/man/man1/ltx2crossrefxml.1
    trunk/Master/texmf-dist/doc/man/man1/ltx2crossrefxml.man1.pdf
    trunk/Master/texmf-dist/doc/support/crossrefware/README
    trunk/Master/texmf-dist/doc/support/crossrefware/crossrefware.pdf
    trunk/Master/texmf-dist/scripts/crossrefware/bibzbladd.pl
    trunk/Master/texmf-dist/scripts/crossrefware/ltx2crossrefxml.pl

Modified: trunk/Build/source/texk/texlive/linked_scripts/crossrefware/bibzbladd.pl
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/crossrefware/bibzbladd.pl	2025-08-30 23:49:33 UTC (rev 76193)
+++ trunk/Build/source/texk/texlive/linked_scripts/crossrefware/bibzbladd.pl	2025-08-31 19:20:16 UTC (rev 76194)
@@ -8,7 +8,7 @@
 
 =head1 SYNOPSIS
 
-bibzbladd  [-d] [B<-f>] [B<-e> 1|0] [B<-o> I<output>] I<bib_file>
+bibzbladd  [-d] [B<-f>] [B<-e> 1|0] [B<-o> I<output>] [B<-p> I<probability>] [B<-v|-q>] I<bib_file>
 
 =head1 OPTIONS
 
@@ -33,6 +33,22 @@
 Output file.  If this option is not used, the name for the 
 output file is formed by adding C<_zbl> to the input file
 
+=item B<-p> I<probability>
+
+Zbmath.org now outputs a probability of match.  We disregard the
+matches with the probability lower than I<probability>.  The default
+is 0.9
+
+=item B<-v>
+
+Verbose mode (the default).  Add to the output the intermediate
+results of zbl search
+
+=item B<-q>
+
+Quiet mode.  Do not add to the output the intermediate results
+of zbl search.
+
 =back
 
 =head1 DESCRIPTION
@@ -52,7 +68,7 @@
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (C) 2014-2024 Boris Veytsman
+Copyright (C) 2014-2025 Boris Veytsman
 
 This is free software.  You may redistribute copies of it under the
 terms of the GNU General Public License
@@ -74,9 +90,10 @@
 use Getopt::Std;
 use URI::Escape;
 use LWP::UserAgent;
+use JSON;
 $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0;
 
-my $USAGE="USAGE: $0  [-d] [-e 1|0] [-f] [-o output] file\n";
+my $USAGE="USAGE: $0  [-d] [-e 1|0] [-f] [-o output] [-p probability] [-v|-q] file\n";
 my $VERSION = <<END;
 bibzbladd v2.3
 This is free software.  You may redistribute copies of it under the
@@ -86,7 +103,7 @@
 $USAGE
 END
 my %opts;
-getopts('de:fo:hV',\%opts) or die $USAGE;
+getopts('de:fo:p:hV',\%opts) or die $USAGE;
 
 if ($opts{h} || $opts{V}){
     print $VERSION;
@@ -116,6 +133,23 @@
 
 my $debug = $opts{d};
 
+my $prob = 0.9;
+if (exists $opts{p}) {
+    $prob = $opts{p};
+}
+
+my $json = JSON->new->allow_nonref;
+
+my $quiet = 0;
+if (exists $opts{q}) {
+    $quiet = 1;
+}
+if (exists $opts{v}) {
+    $quiet = 0;
+}
+
+
+
 my $input= IO::File->new($inputfile) or 
     die "Cannot find BibTeX file $inputfile\n$USAGE\n";
 my $output = IO::File->new("> $outputfile") or 
@@ -188,17 +222,43 @@
 	print STDERR "DEBUG:  response: ",
 	$response->decoded_content, "\n";
     }
-    
-    if ($response->decoded_content =~ /^\s*"zbl_id":\s*"(.*)",?\s*$/m) {
+
+    my $content = $json->decode($response->decoded_content);
+
+    if (!exists $content->{results}) {
 	if ($debug) {
-	    print STDERR "DEBUG:  got zbl: $1\n",
+	    print STDERR "DEBUG: Did not get zbl\n";
 	}
-	return $1;
-     } else {
-	if ($debug) {
-	    print STDERR "DEBUG: Did not get zbl\n",
+	return("");
+    }
+
+    if (!$quiet) {
+	print $output "% ZBL search:\n";
+    }
+    
+    my $results = $content->{results};
+    if (!$quiet) {
+	my $string =  $json->pretty->encode( $results );
+	$string =~ s/^(.)/% \1/mg;
+	print $output "$string\n";
+    }
+
+    foreach my $result (@{$results}) {
+	if (!exists $result->{probability} ||
+	    $result->{probability} < $prob ||
+	    !exists $result->{zbl_id}
+	    ) {
+	    next;
 	}
- 	return ("");
+	my $zbl = $result->{zbl_id};
+ 	if ($debug) {
+ 	    print STDERR "DEBUG:  got zbl: $zbl\n",
+ 	}
+ 	return($zbl);
     }
 
+    if ($debug) {
+	print STDERR "DEBUG: Did not get zbl\n",
+    }
+    return ("");
 }

Modified: trunk/Build/source/texk/texlive/linked_scripts/crossrefware/ltx2crossrefxml.pl
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/crossrefware/ltx2crossrefxml.pl	2025-08-30 23:49:33 UTC (rev 76193)
+++ trunk/Build/source/texk/texlive/linked_scripts/crossrefware/ltx2crossrefxml.pl	2025-08-31 19:20:16 UTC (rev 76194)
@@ -77,9 +77,9 @@
 
 For the definition of the Crossref schema currently output by this
 script, see
-L<https://data.crossref.org/reports/help/schema_doc/5.3.1/index.html>
+L<https://data.crossref.org/reports/help/schema_doc/5.4.0/index.html>
 with additional links and information at
-L<https://www.crossref.org/documentation/schema-library/metadata-deposit-schema-5-3-1/>.
+L<https://www.crossref.org/documentation/schema-library/metadata-deposit-schema-5-4-0/>.
 
 =head1 CONFIGURATION FILE FORMAT
 
@@ -108,7 +108,7 @@
 given C<full_title>, C<issn>, etc., and then each C<.rpi> is written as
 C<journal_issue> plus C<journal_article> elements.
 
-The configuration file can also define one Perl function:
+The configuration file can also define a Perl function
 C<LaTeX_ToUnicode_convert_hook>. If it is defined, it is called at the
 beginning of the procedure that converts LaTeX text to Unicode, which is
 done with the L<LaTeX::ToUnicode> module, from the C<bibtexperllibs>
@@ -119,6 +119,16 @@
 cases, such as control sequences particular to the journal at hand.
 (See TUGboat's C<ltx2crossrefxml-tugboat.cfg> for an example.)
 
+The configuration file can also define a hash C<BibentryToCrossref>) that
+maps Crossref entry types to BibTeX entry types used in the
+bibliography processing (see L<CITATIONS>), for example
+
+  %BibentryToCrossref = ('WEBPAGE' => 'other',
+                         'MISC' => 'other');
+
+The keys in this hash must be in the upper case, while the entries
+must be in the lower case.
+
 =head1 RPI FILE FORMAT
 
 Here's the (relevant part of the) C<.rpi> file corresponding to the
@@ -245,15 +255,50 @@
 The C<.rpi> file is also checked for the bibliography information, in
 this same format.
 
-Crossref's structured citations are added as follows, Aas defined by
-their schema
-(L<https://data.crossref.org/reports/help/schema_doc/5.3.1/common5_3_1_xsd.html#citation>):
-If an C<.aux> file is present, it is checked for any C<\bibdata>
+Crossref's structured citations are added as follows:
+
+=over 4
+
+=item 1. If an C<.aux> file is present, it is checked for any C<\bibdata>
 commands. The C<bib> files in these commands are read, and the
 information there is used to generate XML entries. The script uses
-C<kpsewhich> to look for the bib files, so the usual BibTeX conventions
-for the search paths are followed.
+C<kpsewhich> to look for the bib files, so the usual BibTeX
+conventions for the search paths are followed.
 
+=item 2. For any citation the corresponding entry in the C<bib> file is
+processed.
+
+=item 3. The Crossref entry type is determined according to the algorithm
+describe below (L<CITATION ENTRY TYPES>).
+
+=item 4. The entry fields are used to populate structured citation.
+
+=back
+
+=head2 CITATION ENTRY TYPES
+
+The current Crossref schema
+L<https://data.crossref.org/reports/help/schema_doc/5.4.0/schema_5_4_0.html>
+defines C<type> attribute for a citation.  Unfortunately the list of
+possible types does not fully coincide with the list of BibTeX entry
+types.  Therefore the script uses the following algorithm to determine
+the Crossref entry type for a citation:
+
+=over 4
+
+=item 1. If the entry has the field C<crossrefentrytype>, it is used.
+
+=item 2. Otherwise if BibTeX entry type appears in the hash
+C<BibentryToCrossref>) in the configuration file (L<CONFIGURATION FILE
+FORMAT>), its value is used.
+
+=item 3. Otherwise the default mapping is used.  The script knows many
+BibTeX entry types, and should do a good job in most cases.
+
+=back
+
+
+
 =head1 EXAMPLES
 
   ltx2crossrefxml.pl ../paper1/paper1.tex ../paper2/paper2.tex \
@@ -391,9 +436,47 @@
  our $timestamp = strftime("%Y%m%d%H%M%S", gmtime);
  # use timestamp in batchid, since the value is supposed to be unique
  # for every submission to crossref by a given publisher.
- # https://data.crossref.org/reports/help/schema_doc/5.3.1/common5_3_1_xsd.html#doi_batch_id
+ # https://data.crossref.org/reports/help/schema_doc/5.4.0/schema_5_4_0.html#doi_batch_id
  our $batchId="ltx2crossref-$timestamp-$$";
 
+ # Default mappings of BibTeX entries to Crossref types
+our %BibentryToCrossrefDefault = (
+    # Default types
+    'ARTICLE' => 'journal_article',
+    'BOOK' => 'book',
+    'BOOKLET' => 'book',
+    'CONFERENCE' => 'conference_paper',
+    'INBOOK' => 'book_chapter',
+    'INCOLLECTION' => 'book_chapter',
+    'INPROCEEDINGS' => 'conference_paper',
+    'MANUAL' => 'software',
+    'MASTERSTHESIS' => 'dissertation',
+    'MISC' => 'other',
+    'PHDTHESIS' => 'dissertation',
+    'PROCEEDINGS' => 'conference_proceedings',
+    'TECHREPORT' => 'report',
+    'UNPUBLISHED' => 'other',
+    # From TUGboat
+    'CTAN' => 'software',
+    'ONLINE' => 'web_resource',
+    'SOFTWARE' => 'software',
+    'WEBPAGE' => 'web_resource',
+    # From ACM
+    'UNDERREVIEW' => 'other',
+    'PRESENTATION' => 'poster',
+    'GAME' => 'software',
+    'VIDEO' => 'web_resource',
+    'ARTIFACTSOFTWARE' => 'software',
+    'ARTIFACTDATASET' => 'dataset',
+    'DATASET' => 'dataset',
+    'PRERINT' => 'preprint',
+    # Some other popular types
+    'PATENT' => 'patent',
+    'STANDARD' => 'standard'
+    );
+
+ our %BibentryToCrossref; # empty hash, might be overriden by config
+
  if ($opts{c}) {
      if (-r $opts{c}) {
          # if config arg is absolute, fine; if not, prepend "./" as slightly
@@ -404,7 +487,9 @@
          die "Cannot read config file $opts{c}. Goodbye.";
      }
  }
- 
+
+
+
  PrintHead();
 
  # 
@@ -455,7 +540,7 @@
     # Crossref schema info:
     # https://www.crossref.org/documentation/schema-library/schema-versions/
     print OUT <<END;
-<doi_batch xmlns="http://www.crossref.org/schema/5.3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5.3.1" xsi:schemaLocation="http://www.crossref.org/schema/5.3.1 http://www.crossref.org/schema/deposit/crossref5.3.1.xsd">
+<doi_batch xmlns="http://www.crossref.org/schema/5.4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5.4.0" xsi:schemaLocation="http://www.crossref.org/schema/5.4.0 https://www.crossref.org/schemas/crossref5.4.0.xsd">
   <head>
     <doi_batch_id>$batchId</doi_batch_id>
     <timestamp>$timestamp</timestamp>
@@ -628,12 +713,13 @@
 # Extract bib entries corresponding to the list of keys and convert
 # them to XML structured citations accoding to Crossref
 # scheme at
-# https://data.crossref.org/reports/help/schema_doc/5.3.1/common5_3_1_xsd.html#citation 
+# https://data.crossref.org/reports/help/schema_doc/5.4.0/schema_5_4_0.html#citation 
 # 
 # Return a hash reference, with each element's key being the citation
 # key plus an integer, the same keys as in AddBibliography from the .bbl
-# file. Each value is a flat string, the structured citation items for
-# that element.
+# file. Each value is a hash with two elements:  entrytype being the
+# type of the entry, and citation being  the structured citation items for
+# that entry.
 ##############################################################
 sub AddBibtexBib {
     my ($auxfile,$refs) = @_;
@@ -694,28 +780,52 @@
 
     return \%result;
 }
+

+############################################################## 
+# Get Crossref entry type for a given entry.
+# Returnr a flat string
+##############################################################
+sub CrEntrytype {
+    my $entry=shift;
+    if ($entry->{'crossrefentrytype'}) {
+	&debug("  Found explicit entry type, $entry->{'crossrefentrytype'}\n");
+	return($entry->{'crossrefentrytype'});
+    }
+    
+    my $type = $entry->type;
+    &debug("Bibtex type $type\n");
 
+    if (exists $BibentryToCrossref{$type}) {
+	&debug("  Found a custom mapping $BibentryToCrossref{$type}\n");
+	return($BibentryToCrossref{$type});
+    }
+
+    if (exists $BibentryToCrossrefDefault{$type}) {
+	&debug("  Found a default mapping $BibentryToCrossrefDefault{$type}\n");
+	return($BibentryToCrossrefDefault{$type});
+    }
+
+    &debug("  Cannot find a mapping, returning 'other'\n");
+    return('other');
+}
+
 

 ############################################################## 
 # Convert a BibTeX entry to Crossref structured citation
 # according to
-# data.crossref.org/reports/help/schema_doc/5.3.1/common5_3_1_xsd.html#citation
+# https://data.crossref.org/reports/help/schema_doc/5.4.0/schema_5_4_0.html#citation
 #
-# Return a string.
+# Return a hash with two elements: entrytype and citation
 ##############################################################
 sub ConvertBibentryToCr {
     my $entry = shift;
-    my $result = "";
+    &debug_hash_as_string("Processing citation entry", $entry);
+    my %result = ();
 
-    if (! $entry->{"journal"} && ! $entry->{"issn"}) {
-        # crossref 5.3.1 only supports citations to journal articles; an
-        # upload of anything else gets:
-        # <citation key="whatever-1" status="error">Either ISSN or
-        #    Journal title or Proceedings title must be supplied.</citation>
-        # So we might as well quit now unless we have journal|issn.
-        return "";
-    }
-    $result .= ConvertBibFieldToCfield($entry, 'journal', 'journal_title');
+    $result{'entrytype'} = CrEntrytype($entry);
+    $result{'citation'} = "";
+    
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'journal', 'journal_title');
 
     my $issn = $entry->{"issn"};
     if ($issn && $issn !~ /\d{4}-?\d{3}[\dX]/) {
@@ -723,7 +833,7 @@
         warn "$0: goodbye, invalid issn value: $issn\n";
         die "$0:   ", &debug_hash_as_string("in entry", $entry);
     }
-    $result .= ConvertBibFieldToCfield($entry, 'issn');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'issn');
 
     # Somehow crossref wants only the first author.  Why?
     my @authors = $entry->author;
@@ -732,27 +842,27 @@
     }
     if (scalar(@authors)) {
 	my $author = shift @authors;
-	$result .= "<author>";
-	$result .= SanitizeTextEntities($author->to_string());
-	$result .= "</author>\n";
+	$result{'citation'} .= "<author>";
+	$result{'citation'} .= SanitizeTextEntities($author->to_string());
+	$result{'citation'} .= "</author>\n";
     }
 
-    $result .= ConvertBibFieldToCfield($entry, 'volume');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'volume');
 
-    $result .= ConvertBibFieldToCfield($entry, 'issue');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'issue');
 
     # We need only the first page
     if ($entry->field('pages')) {
 	my $page = $entry->field('pages');
 	$page =~ s/-.*//;
-	$result .= "<first_page>$page</first_page>\n";
+	$result{'citation'} .= "<first_page>$page</first_page>\n";
     }
 
-    $result .= ConvertBibFieldToCfield($entry, 'eprint', 'elocation_id');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'eprint', 'elocation_id');
 
-    $result .= ConvertBibFieldToCfield($entry, 'year', 'cYear');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'year', 'cYear');
 
-    $result .= ConvertBibFieldToCfield($entry, 'doi');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'doi');
 
     my $isbn = $entry->{"isbn"};
     if ($isbn) {
@@ -776,19 +886,19 @@
             die "$0:   ", &debug_hash_as_string("in entry", $entry);
         } else {
             # value apparently ok, use it.
-            $result .= ConvertBibFieldToCfield($entry, 'isbn');
+            $result{'citation'} .= ConvertBibFieldToCfield($entry, 'isbn');
         }
     }
 
-    $result .= ConvertBibFieldToCfield($entry, 'series', 'series_title');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'series', 'series_title');
 
-    $result .= ConvertBibFieldToCfield($entry, 'booktitle', 'volume_title');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'booktitle', 'volume_title');
 
-    $result .= ConvertBibFieldToCfield($entry, 'title', 'article_title');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'title', 'article_title');
     
-    chomp $result; # Delete the last \n
+    chomp $result{'citation'}; # Delete the last \n
     
-    return $result;
+    return \%result;
 }
 
 

@@ -1033,18 +1143,27 @@
             $citation_text = SanitizeTextEntities($citation_text);
 
             &debug("  printing citation $citekey: $citation_text\n");
-            my $structured_citation = $bibtexbib->{$citekey} || "";
-	    if ($structured_citation) {
+            my $structured_citation_hash = $bibtexbib->{$citekey} || "";
+	    if ($structured_citation_hash) {
+		my $entrytype = $structured_citation_hash -> {'entrytype'};
+		my $structured_citation = $structured_citation_hash -> {'citation'};
 		$structured_citation = "\n" . $structured_citation;
 		$structured_citation =~ s/^(.)/          $1/mg;
-		debug ("    with structured citation: $structured_citation\n");
+		&debug ("    with structured citation: $structured_citation\n");
 
-	    }
             print OUT <<END;
-        <citation key="$citekey">$structured_citation
+        <citation key="$citekey" type="$entrytype">$structured_citation
           <unstructured_citation>$citation_text</unstructured_citation>
         </citation>
 END
+	    } else {
+            print OUT <<END;
+        <citation key="$citekey">
+          <unstructured_citation>$citation_text</unstructured_citation>
+        </citation>
+END
+	    }
+		
         }
     }
     print OUT "      </citation_list>\n";

Modified: trunk/Master/texmf-dist/doc/man/man1/bibzbladd.1
===================================================================
--- trunk/Master/texmf-dist/doc/man/man1/bibzbladd.1	2025-08-30 23:49:33 UTC (rev 76193)
+++ trunk/Master/texmf-dist/doc/man/man1/bibzbladd.1	2025-08-31 19:20:16 UTC (rev 76194)
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "bibzbladd 1"
-.TH bibzbladd 1 "2025-05-25" "" "LATEX CROSSREFWARE"
+.TH bibzbladd 1 "2025-08-30" "" "LATEX CROSSREFWARE"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
@@ -142,7 +142,7 @@
 bibzbladd.pl \- add Zbl numbers to papers in a given bib file
 .SH "SYNOPSIS"
 .IX Header "SYNOPSIS"
-bibzbladd  [\-d] [\fB\-f\fR] [\fB\-e\fR 1|0] [\fB\-o\fR \fIoutput\fR] \fIbib_file\fR
+bibzbladd  [\-d] [\fB\-f\fR] [\fB\-e\fR 1|0] [\fB\-o\fR \fIoutput\fR] [\fB\-p\fR \fIprobability\fR] [\fB\-v|\-q\fR] \fIbib_file\fR
 .SH "OPTIONS"
 .IX Header "OPTIONS"
 .IP "\fB\-d\fR" 4
@@ -160,6 +160,19 @@
 .IX Item "-o output"
 Output file.  If this option is not used, the name for the 
 output file is formed by adding \f(CW\*(C`_zbl\*(C'\fR to the input file
+.IP "\fB\-p\fR \fIprobability\fR" 4
+.IX Item "-p probability"
+Zbmath.org now outputs a probability of match.  We disregard the
+matches with the probability lower than \fIprobability\fR.  The default
+is 0.9
+.IP "\fB\-v\fR" 4
+.IX Item "-v"
+Verbose mode (the default).  Add to the output the intermediate
+results of zbl search
+.IP "\fB\-q\fR" 4
+.IX Item "-q"
+Quiet mode.  Do not add to the output the intermediate results
+of zbl search.
 .SH "DESCRIPTION"
 .IX Header "DESCRIPTION"
 The script reads a BibTeX file.  It checks whether the entries have
@@ -175,7 +188,7 @@
 Boris Veytsman
 .SH "COPYRIGHT AND LICENSE"
 .IX Header "COPYRIGHT AND LICENSE"
-Copyright (C) 2014\-2024 Boris Veytsman
+Copyright (C) 2014\-2025 Boris Veytsman
 .PP
 This is free software.  You may redistribute copies of it under the
 terms of the \s-1GNU\s0 General Public License

Modified: trunk/Master/texmf-dist/doc/man/man1/bibzbladd.man1.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/man/man1/ltx2crossrefxml.1
===================================================================
--- trunk/Master/texmf-dist/doc/man/man1/ltx2crossrefxml.1	2025-08-30 23:49:33 UTC (rev 76193)
+++ trunk/Master/texmf-dist/doc/man/man1/ltx2crossrefxml.1	2025-08-31 19:20:16 UTC (rev 76194)
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "ltx2crossrefxml 1"
-.TH ltx2crossrefxml 1 "2025-07-10" "" "LATEX CROSSREFWARE"
+.TH ltx2crossrefxml 1 "2025-07-28" "" "LATEX CROSSREFWARE"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
@@ -202,9 +202,9 @@
 .PP
 For the definition of the Crossref schema currently output by this
 script, see
-<https://data.crossref.org/reports/help/schema_doc/5.3.1/index.html>
+<https://data.crossref.org/reports/help/schema_doc/5.4.0/index.html>
 with additional links and information at
-<https://www.crossref.org/documentation/schema\-library/metadata\-deposit\-schema\-5\-3\-1/>.
+<https://www.crossref.org/documentation/schema\-library/metadata\-deposit\-schema\-5\-4\-0/>.
 .SH "CONFIGURATION FILE FORMAT"
 .IX Header "CONFIGURATION FILE FORMAT"
 The configuration file is read as Perl code. Thus, comment lines
@@ -236,7 +236,7 @@
 given \f(CW\*(C`full_title\*(C'\fR, \f(CW\*(C`issn\*(C'\fR, etc., and then each \f(CW\*(C`.rpi\*(C'\fR is written as
 \&\f(CW\*(C`journal_issue\*(C'\fR plus \f(CW\*(C`journal_article\*(C'\fR elements.
 .PP
-The configuration file can also define one Perl function:
+The configuration file can also define a Perl function
 \&\f(CW\*(C`LaTeX_ToUnicode_convert_hook\*(C'\fR. If it is defined, it is called at the
 beginning of the procedure that converts LaTeX text to Unicode, which is
 done with the LaTeX::ToUnicode module, from the \f(CW\*(C`bibtexperllibs\*(C'\fR
@@ -246,6 +246,18 @@
 the returned string, so the configured function need only handle special
 cases, such as control sequences particular to the journal at hand.
 (See TUGboat's \f(CW\*(C`ltx2crossrefxml\-tugboat.cfg\*(C'\fR for an example.)
+.PP
+The configuration file can also define a hash \f(CW\*(C`BibentryToCrossref\*(C'\fR) that
+maps Crossref entry types to BibTeX entry types used in the
+bibliography processing (see \s-1CITATIONS\s0), for example
+.PP
+.Vb 2
+\&  %BibentryToCrossref = (\*(AqWEBPAGE\*(Aq => \*(Aqother\*(Aq,
+\&                         \*(AqMISC\*(Aq => \*(Aqother\*(Aq);
+.Ve
+.PP
+The keys in this hash must be in the upper case, while the entries
+must be in the lower case.
 .SH "RPI FILE FORMAT"
 .IX Header "RPI FILE FORMAT"
 Here's the (relevant part of the) \f(CW\*(C`.rpi\*(C'\fR file corresponding to the
@@ -376,14 +388,38 @@
 The \f(CW\*(C`.rpi\*(C'\fR file is also checked for the bibliography information, in
 this same format.
 .PP
-Crossref's structured citations are added as follows, Aas defined by
-their schema
-(<https://data.crossref.org/reports/help/schema_doc/5.3.1/common5_3_1_xsd.html#citation>):
-If an \f(CW\*(C`.aux\*(C'\fR file is present, it is checked for any \f(CW\*(C`\ebibdata\*(C'\fR
-commands. The \f(CW\*(C`bib\*(C'\fR files in these commands are read, and the
-information there is used to generate \s-1XML\s0 entries. The script uses
-\&\f(CW\*(C`kpsewhich\*(C'\fR to look for the bib files, so the usual BibTeX conventions
-for the search paths are followed.
+Crossref's structured citations are added as follows:
+.ie n .IP "1. If an "".aux"" file is present, it is checked for any ""\ebibdata"" commands. The ""bib"" files in these commands are read, and the information there is used to generate \s-1XML\s0 entries. The script uses ""kpsewhich"" to look for the bib files, so the usual BibTeX conventions for the search paths are followed." 4
+.el .IP "1. If an \f(CW.aux\fR file is present, it is checked for any \f(CW\ebibdata\fR commands. The \f(CWbib\fR files in these commands are read, and the information there is used to generate \s-1XML\s0 entries. The script uses \f(CWkpsewhich\fR to look for the bib files, so the usual BibTeX conventions for the search paths are followed." 4
+.IX Item "1. If an .aux file is present, it is checked for any bibdata commands. The bib files in these commands are read, and the information there is used to generate XML entries. The script uses kpsewhich to look for the bib files, so the usual BibTeX conventions for the search paths are followed."
+.PD 0
+.ie n .IP "2. For any citation the corresponding entry in the ""bib"" file is processed." 4
+.el .IP "2. For any citation the corresponding entry in the \f(CWbib\fR file is processed." 4
+.IX Item "2. For any citation the corresponding entry in the bib file is processed."
+.ie n .IP "3. The Crossref entry type is determined according to the algorithm describe below (""\s-1CITATION ENTRY TYPES""\s0)." 4
+.el .IP "3. The Crossref entry type is determined according to the algorithm describe below (``\s-1CITATION ENTRY TYPES''\s0)." 4
+.IX Item "3. The Crossref entry type is determined according to the algorithm describe below (CITATION ENTRY TYPES)."
+.IP "4. The entry fields are used to populate structured citation." 4
+.IX Item "4. The entry fields are used to populate structured citation."
+.PD
+.SS "\s-1CITATION ENTRY TYPES\s0"
+.IX Subsection "CITATION ENTRY TYPES"
+The current Crossref schema
+<https://data.crossref.org/reports/help/schema_doc/5.4.0/schema_5_4_0.html>
+defines \f(CW\*(C`type\*(C'\fR attribute for a citation.  Unfortunately the list of
+possible types does not fully coincide with the list of BibTeX entry
+types.  Therefore the script uses the following algorithm to determine
+the Crossref entry type for a citation:
+.ie n .IP "1. If the entry has the field ""crossrefentrytype"", it is used." 4
+.el .IP "1. If the entry has the field \f(CWcrossrefentrytype\fR, it is used." 4
+.IX Item "1. If the entry has the field crossrefentrytype, it is used."
+.PD 0
+.ie n .IP "2. Otherwise if BibTeX entry type appears in the hash ""BibentryToCrossref"") in the configuration file (""\s-1CONFIGURATION FILE FORMAT""\s0), its value is used." 4
+.el .IP "2. Otherwise if BibTeX entry type appears in the hash \f(CWBibentryToCrossref\fR) in the configuration file (``\s-1CONFIGURATION FILE FORMAT''\s0), its value is used." 4
+.IX Item "2. Otherwise if BibTeX entry type appears in the hash BibentryToCrossref) in the configuration file (CONFIGURATION FILE FORMAT), its value is used."
+.IP "3. Otherwise the default mapping is used.  The script knows many BibTeX entry types, and should do a good job in most cases." 4
+.IX Item "3. Otherwise the default mapping is used. The script knows many BibTeX entry types, and should do a good job in most cases."
+.PD
 .SH "EXAMPLES"
 .IX Header "EXAMPLES"
 .Vb 2

Modified: trunk/Master/texmf-dist/doc/man/man1/ltx2crossrefxml.man1.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/support/crossrefware/README
===================================================================
--- trunk/Master/texmf-dist/doc/support/crossrefware/README	2025-08-30 23:49:33 UTC (rev 76193)
+++ trunk/Master/texmf-dist/doc/support/crossrefware/README	2025-08-31 19:20:16 UTC (rev 76194)
@@ -1,5 +1,5 @@
 			 Crossrefware Bundle
-			  version 2025-07-09
+			  version 2025-08-30
 
 Scripts useful for working with Crossref, MathSciNet and Zentralblatt MATH.
 
@@ -30,6 +30,10 @@
 
 Changes:
 
+2025-08-30    - Redesigned bibzbladd due to changes in zbmath output.
+                Now the user can select the cutoff probability to
+		accept the search results.
+
 2025-07-09    - Use entities in structured citation output;
                 avoid uploading unaccepted structured citations
 

Modified: trunk/Master/texmf-dist/doc/support/crossrefware/crossrefware.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/scripts/crossrefware/bibzbladd.pl
===================================================================
--- trunk/Master/texmf-dist/scripts/crossrefware/bibzbladd.pl	2025-08-30 23:49:33 UTC (rev 76193)
+++ trunk/Master/texmf-dist/scripts/crossrefware/bibzbladd.pl	2025-08-31 19:20:16 UTC (rev 76194)
@@ -8,7 +8,7 @@
 
 =head1 SYNOPSIS
 
-bibzbladd  [-d] [B<-f>] [B<-e> 1|0] [B<-o> I<output>] I<bib_file>
+bibzbladd  [-d] [B<-f>] [B<-e> 1|0] [B<-o> I<output>] [B<-p> I<probability>] [B<-v|-q>] I<bib_file>
 
 =head1 OPTIONS
 
@@ -33,6 +33,22 @@
 Output file.  If this option is not used, the name for the 
 output file is formed by adding C<_zbl> to the input file
 
+=item B<-p> I<probability>
+
+Zbmath.org now outputs a probability of match.  We disregard the
+matches with the probability lower than I<probability>.  The default
+is 0.9
+
+=item B<-v>
+
+Verbose mode (the default).  Add to the output the intermediate
+results of zbl search
+
+=item B<-q>
+
+Quiet mode.  Do not add to the output the intermediate results
+of zbl search.
+
 =back
 
 =head1 DESCRIPTION
@@ -52,7 +68,7 @@
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (C) 2014-2024 Boris Veytsman
+Copyright (C) 2014-2025 Boris Veytsman
 
 This is free software.  You may redistribute copies of it under the
 terms of the GNU General Public License
@@ -74,9 +90,10 @@
 use Getopt::Std;
 use URI::Escape;
 use LWP::UserAgent;
+use JSON;
 $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0;
 
-my $USAGE="USAGE: $0  [-d] [-e 1|0] [-f] [-o output] file\n";
+my $USAGE="USAGE: $0  [-d] [-e 1|0] [-f] [-o output] [-p probability] [-v|-q] file\n";
 my $VERSION = <<END;
 bibzbladd v2.3
 This is free software.  You may redistribute copies of it under the
@@ -86,7 +103,7 @@
 $USAGE
 END
 my %opts;
-getopts('de:fo:hV',\%opts) or die $USAGE;
+getopts('de:fo:p:hV',\%opts) or die $USAGE;
 
 if ($opts{h} || $opts{V}){
     print $VERSION;
@@ -116,6 +133,23 @@
 
 my $debug = $opts{d};
 
+my $prob = 0.9;
+if (exists $opts{p}) {
+    $prob = $opts{p};
+}
+
+my $json = JSON->new->allow_nonref;
+
+my $quiet = 0;
+if (exists $opts{q}) {
+    $quiet = 1;
+}
+if (exists $opts{v}) {
+    $quiet = 0;
+}
+
+
+
 my $input= IO::File->new($inputfile) or 
     die "Cannot find BibTeX file $inputfile\n$USAGE\n";
 my $output = IO::File->new("> $outputfile") or 
@@ -188,17 +222,43 @@
 	print STDERR "DEBUG:  response: ",
 	$response->decoded_content, "\n";
     }
-    
-    if ($response->decoded_content =~ /^\s*"zbl_id":\s*"(.*)",?\s*$/m) {
+
+    my $content = $json->decode($response->decoded_content);
+
+    if (!exists $content->{results}) {
 	if ($debug) {
-	    print STDERR "DEBUG:  got zbl: $1\n",
+	    print STDERR "DEBUG: Did not get zbl\n";
 	}
-	return $1;
-     } else {
-	if ($debug) {
-	    print STDERR "DEBUG: Did not get zbl\n",
+	return("");
+    }
+
+    if (!$quiet) {
+	print $output "% ZBL search:\n";
+    }
+    
+    my $results = $content->{results};
+    if (!$quiet) {
+	my $string =  $json->pretty->encode( $results );
+	$string =~ s/^(.)/% \1/mg;
+	print $output "$string\n";
+    }
+
+    foreach my $result (@{$results}) {
+	if (!exists $result->{probability} ||
+	    $result->{probability} < $prob ||
+	    !exists $result->{zbl_id}
+	    ) {
+	    next;
 	}
- 	return ("");
+	my $zbl = $result->{zbl_id};
+ 	if ($debug) {
+ 	    print STDERR "DEBUG:  got zbl: $zbl\n",
+ 	}
+ 	return($zbl);
     }
 
+    if ($debug) {
+	print STDERR "DEBUG: Did not get zbl\n",
+    }
+    return ("");
 }

Modified: trunk/Master/texmf-dist/scripts/crossrefware/ltx2crossrefxml.pl
===================================================================
--- trunk/Master/texmf-dist/scripts/crossrefware/ltx2crossrefxml.pl	2025-08-30 23:49:33 UTC (rev 76193)
+++ trunk/Master/texmf-dist/scripts/crossrefware/ltx2crossrefxml.pl	2025-08-31 19:20:16 UTC (rev 76194)
@@ -77,9 +77,9 @@
 
 For the definition of the Crossref schema currently output by this
 script, see
-L<https://data.crossref.org/reports/help/schema_doc/5.3.1/index.html>
+L<https://data.crossref.org/reports/help/schema_doc/5.4.0/index.html>
 with additional links and information at
-L<https://www.crossref.org/documentation/schema-library/metadata-deposit-schema-5-3-1/>.
+L<https://www.crossref.org/documentation/schema-library/metadata-deposit-schema-5-4-0/>.
 
 =head1 CONFIGURATION FILE FORMAT
 
@@ -108,7 +108,7 @@
 given C<full_title>, C<issn>, etc., and then each C<.rpi> is written as
 C<journal_issue> plus C<journal_article> elements.
 
-The configuration file can also define one Perl function:
+The configuration file can also define a Perl function
 C<LaTeX_ToUnicode_convert_hook>. If it is defined, it is called at the
 beginning of the procedure that converts LaTeX text to Unicode, which is
 done with the L<LaTeX::ToUnicode> module, from the C<bibtexperllibs>
@@ -119,6 +119,16 @@
 cases, such as control sequences particular to the journal at hand.
 (See TUGboat's C<ltx2crossrefxml-tugboat.cfg> for an example.)
 
+The configuration file can also define a hash C<BibentryToCrossref>) that
+maps Crossref entry types to BibTeX entry types used in the
+bibliography processing (see L<CITATIONS>), for example
+
+  %BibentryToCrossref = ('WEBPAGE' => 'other',
+                         'MISC' => 'other');
+
+The keys in this hash must be in the upper case, while the entries
+must be in the lower case.
+
 =head1 RPI FILE FORMAT
 
 Here's the (relevant part of the) C<.rpi> file corresponding to the
@@ -245,15 +255,50 @@
 The C<.rpi> file is also checked for the bibliography information, in
 this same format.
 
-Crossref's structured citations are added as follows, Aas defined by
-their schema
-(L<https://data.crossref.org/reports/help/schema_doc/5.3.1/common5_3_1_xsd.html#citation>):
-If an C<.aux> file is present, it is checked for any C<\bibdata>
+Crossref's structured citations are added as follows:
+
+=over 4
+
+=item 1. If an C<.aux> file is present, it is checked for any C<\bibdata>
 commands. The C<bib> files in these commands are read, and the
 information there is used to generate XML entries. The script uses
-C<kpsewhich> to look for the bib files, so the usual BibTeX conventions
-for the search paths are followed.
+C<kpsewhich> to look for the bib files, so the usual BibTeX
+conventions for the search paths are followed.
 
+=item 2. For any citation the corresponding entry in the C<bib> file is
+processed.
+
+=item 3. The Crossref entry type is determined according to the algorithm
+describe below (L<CITATION ENTRY TYPES>).
+
+=item 4. The entry fields are used to populate structured citation.
+
+=back
+
+=head2 CITATION ENTRY TYPES
+
+The current Crossref schema
+L<https://data.crossref.org/reports/help/schema_doc/5.4.0/schema_5_4_0.html>
+defines C<type> attribute for a citation.  Unfortunately the list of
+possible types does not fully coincide with the list of BibTeX entry
+types.  Therefore the script uses the following algorithm to determine
+the Crossref entry type for a citation:
+
+=over 4
+
+=item 1. If the entry has the field C<crossrefentrytype>, it is used.
+
+=item 2. Otherwise if BibTeX entry type appears in the hash
+C<BibentryToCrossref>) in the configuration file (L<CONFIGURATION FILE
+FORMAT>), its value is used.
+
+=item 3. Otherwise the default mapping is used.  The script knows many
+BibTeX entry types, and should do a good job in most cases.
+
+=back
+
+
+
 =head1 EXAMPLES
 
   ltx2crossrefxml.pl ../paper1/paper1.tex ../paper2/paper2.tex \
@@ -391,9 +436,47 @@
  our $timestamp = strftime("%Y%m%d%H%M%S", gmtime);
  # use timestamp in batchid, since the value is supposed to be unique
  # for every submission to crossref by a given publisher.
- # https://data.crossref.org/reports/help/schema_doc/5.3.1/common5_3_1_xsd.html#doi_batch_id
+ # https://data.crossref.org/reports/help/schema_doc/5.4.0/schema_5_4_0.html#doi_batch_id
  our $batchId="ltx2crossref-$timestamp-$$";
 
+ # Default mappings of BibTeX entries to Crossref types
+our %BibentryToCrossrefDefault = (
+    # Default types
+    'ARTICLE' => 'journal_article',
+    'BOOK' => 'book',
+    'BOOKLET' => 'book',
+    'CONFERENCE' => 'conference_paper',
+    'INBOOK' => 'book_chapter',
+    'INCOLLECTION' => 'book_chapter',
+    'INPROCEEDINGS' => 'conference_paper',
+    'MANUAL' => 'software',
+    'MASTERSTHESIS' => 'dissertation',
+    'MISC' => 'other',
+    'PHDTHESIS' => 'dissertation',
+    'PROCEEDINGS' => 'conference_proceedings',
+    'TECHREPORT' => 'report',
+    'UNPUBLISHED' => 'other',
+    # From TUGboat
+    'CTAN' => 'software',
+    'ONLINE' => 'web_resource',
+    'SOFTWARE' => 'software',
+    'WEBPAGE' => 'web_resource',
+    # From ACM
+    'UNDERREVIEW' => 'other',
+    'PRESENTATION' => 'poster',
+    'GAME' => 'software',
+    'VIDEO' => 'web_resource',
+    'ARTIFACTSOFTWARE' => 'software',
+    'ARTIFACTDATASET' => 'dataset',
+    'DATASET' => 'dataset',
+    'PRERINT' => 'preprint',
+    # Some other popular types
+    'PATENT' => 'patent',
+    'STANDARD' => 'standard'
+    );
+
+ our %BibentryToCrossref; # empty hash, might be overriden by config
+
  if ($opts{c}) {
      if (-r $opts{c}) {
          # if config arg is absolute, fine; if not, prepend "./" as slightly
@@ -404,7 +487,9 @@
          die "Cannot read config file $opts{c}. Goodbye.";
      }
  }
- 
+
+
+
  PrintHead();
 
  # 
@@ -455,7 +540,7 @@
     # Crossref schema info:
     # https://www.crossref.org/documentation/schema-library/schema-versions/
     print OUT <<END;
-<doi_batch xmlns="http://www.crossref.org/schema/5.3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5.3.1" xsi:schemaLocation="http://www.crossref.org/schema/5.3.1 http://www.crossref.org/schema/deposit/crossref5.3.1.xsd">
+<doi_batch xmlns="http://www.crossref.org/schema/5.4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5.4.0" xsi:schemaLocation="http://www.crossref.org/schema/5.4.0 https://www.crossref.org/schemas/crossref5.4.0.xsd">
   <head>
     <doi_batch_id>$batchId</doi_batch_id>
     <timestamp>$timestamp</timestamp>
@@ -628,12 +713,13 @@
 # Extract bib entries corresponding to the list of keys and convert
 # them to XML structured citations accoding to Crossref
 # scheme at
-# https://data.crossref.org/reports/help/schema_doc/5.3.1/common5_3_1_xsd.html#citation 
+# https://data.crossref.org/reports/help/schema_doc/5.4.0/schema_5_4_0.html#citation 
 # 
 # Return a hash reference, with each element's key being the citation
 # key plus an integer, the same keys as in AddBibliography from the .bbl
-# file. Each value is a flat string, the structured citation items for
-# that element.
+# file. Each value is a hash with two elements:  entrytype being the
+# type of the entry, and citation being  the structured citation items for
+# that entry.
 ##############################################################
 sub AddBibtexBib {
     my ($auxfile,$refs) = @_;
@@ -694,28 +780,52 @@
 
     return \%result;
 }
+

+############################################################## 
+# Get Crossref entry type for a given entry.
+# Returnr a flat string
+##############################################################
+sub CrEntrytype {
+    my $entry=shift;
+    if ($entry->{'crossrefentrytype'}) {
+	&debug("  Found explicit entry type, $entry->{'crossrefentrytype'}\n");
+	return($entry->{'crossrefentrytype'});
+    }
+    
+    my $type = $entry->type;
+    &debug("Bibtex type $type\n");
 
+    if (exists $BibentryToCrossref{$type}) {
+	&debug("  Found a custom mapping $BibentryToCrossref{$type}\n");
+	return($BibentryToCrossref{$type});
+    }
+
+    if (exists $BibentryToCrossrefDefault{$type}) {
+	&debug("  Found a default mapping $BibentryToCrossrefDefault{$type}\n");
+	return($BibentryToCrossrefDefault{$type});
+    }
+
+    &debug("  Cannot find a mapping, returning 'other'\n");
+    return('other');
+}
+
 

 ############################################################## 
 # Convert a BibTeX entry to Crossref structured citation
 # according to
-# data.crossref.org/reports/help/schema_doc/5.3.1/common5_3_1_xsd.html#citation
+# https://data.crossref.org/reports/help/schema_doc/5.4.0/schema_5_4_0.html#citation
 #
-# Return a string.
+# Return a hash with two elements: entrytype and citation
 ##############################################################
 sub ConvertBibentryToCr {
     my $entry = shift;
-    my $result = "";
+    &debug_hash_as_string("Processing citation entry", $entry);
+    my %result = ();
 
-    if (! $entry->{"journal"} && ! $entry->{"issn"}) {
-        # crossref 5.3.1 only supports citations to journal articles; an
-        # upload of anything else gets:
-        # <citation key="whatever-1" status="error">Either ISSN or
-        #    Journal title or Proceedings title must be supplied.</citation>
-        # So we might as well quit now unless we have journal|issn.
-        return "";
-    }
-    $result .= ConvertBibFieldToCfield($entry, 'journal', 'journal_title');
+    $result{'entrytype'} = CrEntrytype($entry);
+    $result{'citation'} = "";
+    
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'journal', 'journal_title');
 
     my $issn = $entry->{"issn"};
     if ($issn && $issn !~ /\d{4}-?\d{3}[\dX]/) {
@@ -723,7 +833,7 @@
         warn "$0: goodbye, invalid issn value: $issn\n";
         die "$0:   ", &debug_hash_as_string("in entry", $entry);
     }
-    $result .= ConvertBibFieldToCfield($entry, 'issn');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'issn');
 
     # Somehow crossref wants only the first author.  Why?
     my @authors = $entry->author;
@@ -732,27 +842,27 @@
     }
     if (scalar(@authors)) {
 	my $author = shift @authors;
-	$result .= "<author>";
-	$result .= SanitizeTextEntities($author->to_string());
-	$result .= "</author>\n";
+	$result{'citation'} .= "<author>";
+	$result{'citation'} .= SanitizeTextEntities($author->to_string());
+	$result{'citation'} .= "</author>\n";
     }
 
-    $result .= ConvertBibFieldToCfield($entry, 'volume');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'volume');
 
-    $result .= ConvertBibFieldToCfield($entry, 'issue');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'issue');
 
     # We need only the first page
     if ($entry->field('pages')) {
 	my $page = $entry->field('pages');
 	$page =~ s/-.*//;
-	$result .= "<first_page>$page</first_page>\n";
+	$result{'citation'} .= "<first_page>$page</first_page>\n";
     }
 
-    $result .= ConvertBibFieldToCfield($entry, 'eprint', 'elocation_id');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'eprint', 'elocation_id');
 
-    $result .= ConvertBibFieldToCfield($entry, 'year', 'cYear');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'year', 'cYear');
 
-    $result .= ConvertBibFieldToCfield($entry, 'doi');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'doi');
 
     my $isbn = $entry->{"isbn"};
     if ($isbn) {
@@ -776,19 +886,19 @@
             die "$0:   ", &debug_hash_as_string("in entry", $entry);
         } else {
             # value apparently ok, use it.
-            $result .= ConvertBibFieldToCfield($entry, 'isbn');
+            $result{'citation'} .= ConvertBibFieldToCfield($entry, 'isbn');
         }
     }
 
-    $result .= ConvertBibFieldToCfield($entry, 'series', 'series_title');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'series', 'series_title');
 
-    $result .= ConvertBibFieldToCfield($entry, 'booktitle', 'volume_title');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'booktitle', 'volume_title');
 
-    $result .= ConvertBibFieldToCfield($entry, 'title', 'article_title');
+    $result{'citation'} .= ConvertBibFieldToCfield($entry, 'title', 'article_title');
     
-    chomp $result; # Delete the last \n
+    chomp $result{'citation'}; # Delete the last \n
     
-    return $result;
+    return \%result;
 }
 
 

@@ -1033,18 +1143,27 @@
             $citation_text = SanitizeTextEntities($citation_text);
 
             &debug("  printing citation $citekey: $citation_text\n");
-            my $structured_citation = $bibtexbib->{$citekey} || "";
-	    if ($structured_citation) {
+            my $structured_citation_hash = $bibtexbib->{$citekey} || "";
+	    if ($structured_citation_hash) {
+		my $entrytype = $structured_citation_hash -> {'entrytype'};
+		my $structured_citation = $structured_citation_hash -> {'citation'};
 		$structured_citation = "\n" . $structured_citation;
 		$structured_citation =~ s/^(.)/          $1/mg;
-		debug ("    with structured citation: $structured_citation\n");
+		&debug ("    with structured citation: $structured_citation\n");
 
-	    }
             print OUT <<END;
-        <citation key="$citekey">$structured_citation
+        <citation key="$citekey" type="$entrytype">$structured_citation
           <unstructured_citation>$citation_text</unstructured_citation>
         </citation>
 END
+	    } else {
+            print OUT <<END;
+        <citation key="$citekey">
+          <unstructured_citation>$citation_text</unstructured_citation>
+        </citation>
+END
+	    }
+		
         }
     }
     print OUT "      </citation_list>\n";



More information about the tex-live-commits mailing list.