diff --git a/data/schemata/bcf.rnc b/data/schemata/bcf.rnc
index 71e5e26e8..01d3296a7 100644
--- a/data/schemata/bcf.rnc
+++ b/data/schemata/bcf.rnc
@@ -845,6 +845,7 @@ map =
attribute map_field_set { xsd:string {minLength="1"} }?,
attribute map_entry_null { "1" }?,
attribute map_append { "1" }?,
+ attribute map_appendstrict { "1" }?,
attribute map_final { "1" }?,
attribute map_match { xsd:string {minLength="1"} }?,
attribute map_matchi { xsd:string {minLength="1"} }?,
diff --git a/data/schemata/bcf.rng b/data/schemata/bcf.rng
index 8863af1ed..c68b73313 100644
--- a/data/schemata/bcf.rng
+++ b/data/schemata/bcf.rng
@@ -2187,6 +2187,11 @@
1
+
+
+ 1
+
+
1
diff --git a/data/schemata/config.rnc b/data/schemata/config.rnc
index 54bff65db..a37380d60 100644
--- a/data/schemata/config.rnc
+++ b/data/schemata/config.rnc
@@ -324,6 +324,7 @@ map =
attribute map_field_set { xsd:string {minLength="1"} }?,
attribute map_entry_null { "1" }?,
attribute map_append { "1" }?,
+ attribute map_appendstrict { "1" }?,
attribute map_final { "1" }?,
attribute map_match { xsd:string {minLength="1"} }?,
attribute map_matchi { xsd:string {minLength="1"} }?,
diff --git a/data/schemata/config.rng b/data/schemata/config.rng
index 2f01a7920..f57dba04d 100644
--- a/data/schemata/config.rng
+++ b/data/schemata/config.rng
@@ -1094,6 +1094,11 @@
1
+
+
+ 1
+
+
1
diff --git a/doc/biber.tex b/doc/biber.tex
index c062781f9..b46e0fd8b 100644
--- a/doc/biber.tex
+++ b/doc/biber.tex
@@ -827,6 +827,7 @@ \subsubsection{The \texttt{sourcemap} option}\label{ref:map}
+\textcolor{blue}{map\_entry\_newtype="\textcolor{red}{newentrykeytype}"}+
+\textcolor{blue}{map\_entry\_entrytarget="\textcolor{red}{newentrykey}"}+
+\textcolor{blue}{map\_append="1"}+
+ +\textcolor{blue}{map\_appendstrict="1"}+
+\textcolor{blue}{map\_null="1"}+
+\textcolor{blue}{map\_entry\_null="1"}+
+\textcolor{blue}{map\_entry\_clone="\textcolor{red}{clonekey}"}+
@@ -938,9 +939,10 @@ \subsubsection{The \texttt{sourcemap} option}\label{ref:map}
\textcolor{blue}{\texttt{map\_final}} is also set on this step, then
processing of the parent map stops at this point. If
\textcolor{blue}{\texttt{map\_append}} is set, then the value to set is
- appended to the current value of \textcolor{red}{\texttt{set-field}}. The
- value to set is specified by a mandatory one and only one of the
- following attributes:
+ appended to the current value of \textcolor{red}{\texttt{set-field}}.
+ \textcolor{blue}{\texttt{map\_appendstrict}} appends only if the
+ \textcolor{red}{\texttt{set-field}} is not empty. The value to set is
+ specified by a mandatory one and only one of the following attributes:
\begin{itemize}
\item \textcolor{blue}{\texttt{map\_field\_value}} --- The
\textcolor{red}{\texttt{set-field}} is set to
diff --git a/lib/Biber/Input/file/biblatexml.pm b/lib/Biber/Input/file/biblatexml.pm
index 86c5ab14b..f8419241e 100644
--- a/lib/Biber/Input/file/biblatexml.pm
+++ b/lib/Biber/Input/file/biblatexml.pm
@@ -627,8 +627,12 @@ sub create_entry {
}
}
- # If append is set, keep the original value and append the new
- my $orig = $step->{map_append} ? $etarget->findvalue($xp_node) : '';
+ my $orig = '';
+ # If append or appendstrict is set, keep the original value
+ # and append the new.
+ if ($step->{map_append} or $step->{map_appendstrict}) {
+ $orig = $etarget->findvalue($xp_node) || '';
+ }
if ($step->{map_origentrytype}) {
next unless $last_type;
@@ -636,7 +640,7 @@ sub create_entry {
$logger->debug("Source mapping (type=$level, key=$etargetkey): Setting xpath '$xp_node_s' to '${orig}${last_type}'");
}
- unless (_changenode($etarget, $xp_node_s, $orig . $last_type, \$cnerror)) {
+ unless (_changenode($etarget, $xp_node_s, appendstrict_check($step, $orig, $last_type), \$cnerror)) {
biber_warn("Source mapping (type=$level, key=$key): $cnerror");
}
}
@@ -645,7 +649,7 @@ sub create_entry {
if ($logger->is_debug()) {# performance tune
$logger->debug("Source mapping (type=$level, key=$etargetkey): Setting field xpath '$xp_node_s' to '${orig}${last_fieldval}'");
}
- unless (_changenode($etarget, $xp_node_s, $orig . $last_fieldval, \$cnerror)) {
+ unless (_changenode($etarget, $xp_node_s, appendstrict_check($step, $orig, $last_fieldval), \$cnerror)) {
biber_warn("Source mapping (type=$level, key=$etargetkey): $cnerror");
}
}
@@ -654,7 +658,7 @@ sub create_entry {
if ($logger->is_debug()) {# performance tune
$logger->debug("Source mapping (type=$level, key=$etargetkey): Setting field xpath '$xp_node_s' to '${orig}${last_field}'");
}
- unless (_changenode($etarget, $xp_node_s, $orig . $last_field, \$cnerror)) {
+ unless (_changenode($etarget, $xp_node_s, appendstrict_check($step, $orig, $last_field), \$cnerror)) {
biber_warn("Source mapping (type=$level, key=$etargetkey): $cnerror");
}
}
@@ -667,7 +671,7 @@ sub create_entry {
if ($logger->is_debug()) {# performance tune
$logger->debug("Source mapping (type=$level, key=$etargetkey): Setting field xpath '$xp_node_s' to '${orig}${fv}'");
}
- unless (_changenode($etarget, $xp_node_s, $orig . $fv, \$cnerror)) {
+ unless (_changenode($etarget, $xp_node_s, appendstrict_check($step, $orig, $fv), \$cnerror)) {
biber_warn("Source mapping (type=$level, key=$key): $cnerror");
}
}
diff --git a/lib/Biber/Input/file/bibtex.pm b/lib/Biber/Input/file/bibtex.pm
index b640a9351..7eb01807e 100644
--- a/lib/Biber/Input/file/bibtex.pm
+++ b/lib/Biber/Input/file/bibtex.pm
@@ -708,29 +708,33 @@ sub create_entry {
}
}
- # If append is set, keep the original value and append the new
- my $orig = $step->{map_append} ? $etarget->get($field) : '';
+ my $orig = '';
+ # If append or appendstrict is set, keep the original value
+ # and append the new.
+ if ($step->{map_append} or $step->{map_appendstrict}) {
+ $orig = $etarget->get($field) || '';
+ }
if ($step->{map_origentrytype}) {
next unless $last_type;
if ($logger->is_debug()) { # performance tune
$logger->debug("Source mapping (type=$level, key=$etargetkey): Setting field '$field' to '${orig}${last_type}'");
}
- $etarget->set($field, encode('UTF-8', NFC($orig . $last_type)));
+ $etarget->set($field, encode('UTF-8', NFC(appendstrict_check($step, $orig,$last_type))));
}
elsif ($step->{map_origfieldval}) {
next unless $last_fieldval;
if ($logger->is_debug()) { # performance tune
$logger->debug("Source mapping (type=$level, key=$etargetkey): Setting field '$field' to '${orig}${last_fieldval}'");
}
- $etarget->set($field, encode('UTF-8', NFC($orig . $last_fieldval)));
+ $etarget->set($field, encode('UTF-8', NFC(appendstrict_check($step, $orig, $last_fieldval))));
}
elsif ($step->{map_origfield}) {
next unless $last_field;
if ($logger->is_debug()) { # performance tune
$logger->debug("Source mapping (type=$level, key=$etargetkey): Setting field '$field' to '${orig}${last_field}'");
}
- $etarget->set($field, encode('UTF-8', NFC($orig . $last_field)));
+ $etarget->set($field, encode('UTF-8', NFC(appendstrict_check($step, $orig, $last_field))));
}
else {
my $fv = maploopreplace($step->{map_field_value}, $maploop);
@@ -741,7 +745,7 @@ sub create_entry {
if ($logger->is_debug()) { # performance tune
$logger->debug("Source mapping (type=$level, key=$etargetkey): Setting field '$field' to '${orig}${fv}'");
}
- $etarget->set($field, encode('UTF-8', NFC($orig . $fv)));
+ $etarget->set($field, encode('UTF-8', NFC(appendstrict_check($step, $orig, $fv))));
}
}
}
diff --git a/lib/Biber/Utils.pm b/lib/Biber/Utils.pm
index 794bf52cf..84912107b 100644
--- a/lib/Biber/Utils.pm
+++ b/lib/Biber/Utils.pm
@@ -55,7 +55,7 @@ our @EXPORT = qw{ glob_data_file locate_data_file makenamesid makenameid stringi
bcp472locale rangelen match_indices process_comment map_boolean
parse_range parse_range_alt maploopreplace get_transliterator
call_transliterator normalise_string_bblxml gen_initials join_name_parts
- split_xsv date_monthday tzformat expand_option strip_annotation};
+ split_xsv date_monthday tzformat expand_option strip_annotation appendstrict_check};
=head1 FUNCTIONS
@@ -1657,6 +1657,24 @@ sub tzformat {
}
}
+# Wrapper to enforce map_appendstrict
+sub appendstrict_check {
+ my ($step, $orig, $val) = @_;
+ # Strict append?
+ if ($step->{map_appendstrict}) {
+ if ($orig) {
+ return $orig . $val;
+ }
+ else { # orig is empty, don't append
+ return '';
+ }
+ }
+ # Normal append, don't care if orig is empty
+ else {
+ return $orig . $val;
+ }
+}
+
1;
__END__
diff --git a/t/bibtex-aliases.t b/t/bibtex-aliases.t
index d72b58982..92193da6b 100644
--- a/t/bibtex-aliases.t
+++ b/t/bibtex-aliases.t
@@ -4,7 +4,7 @@ use warnings;
use utf8;
no warnings 'utf8';
-use Test::More tests => 24;
+use Test::More tests => 25;
use Test::Differences;
unified_diff;
@@ -92,3 +92,6 @@ is_deeply($bibentries->entry('alias7')->get_field('lista'), ['listaval'], 'Alias
# Testing append overwrites
eq_or_diff($bibentries->entry('alias7')->get_field('verbb'), 'val2val1', 'Alias - 23' );
eq_or_diff($bibentries->entry('alias7')->get_field('verbc'), 'val3val2val1', 'Alias - 24' );
+
+# Testing appendstrict
+ok(is_undef($bibentries->entry('alias8')->get_field('verbc')), 'Alias - 25' );
diff --git a/t/tdata/bibtex-aliases.bcf b/t/tdata/bibtex-aliases.bcf
index 575c9c678..826052334 100644
--- a/t/tdata/bibtex-aliases.bcf
+++ b/t/tdata/bibtex-aliases.bcf
@@ -551,7 +551,7 @@
-
+
@@ -1936,6 +1936,7 @@
alias5
alias6
alias7
+ alias8
diff --git a/t/tdata/bibtex-aliases.bib b/t/tdata/bibtex-aliases.bib
index 4a1f5e21b..e657eb971 100644
--- a/t/tdata/bibtex-aliases.bib
+++ b/t/tdata/bibtex-aliases.bib
@@ -55,5 +55,10 @@ @REPORT{alias7
LISTA = {listaval},
VERBA = {val1},
VERBB = {val2},
- VERBC = {val3},
+ VERBC = {val3}
+}
+
+@REPORT{alias8,
+ VERBA = {val2},
+ VERBB = {val2}
}