Bug 20540: Fix TransformHtmlToXml if last tag is empty
authorJonathan Druart <jonathan.druart@bugs.koha-community.org>
Fri, 6 Apr 2018 20:16:30 +0000 (17:16 -0300)
committerJonathan Druart <jonathan.druart@bugs.koha-community.org>
Wed, 11 Apr 2018 19:45:19 +0000 (16:45 -0300)
This bug has been found during testing bug 19289.

In some conditions C4::Biblio::TransformHtmlToXml will generate a malformed XML structure. The last </datafield> can be duplicated.

For instance, if a call like:
my $xml = TransformHtmlToXml( \@tags, \@subfields, \@field_values );

with the last value of @field_values is empty, it will return:

<?xml version="1.0" encoding="UTF-8"?>
<collection
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"
  xmlns="http://www.loc.gov/MARC21/slim">
<record>
<datafield2 tag="020" ind1=" " ind2=" ">
<subfield code="a">l</subfield>
</datafield>
<datafield1 tag="100" ind1=" " ind2=" ">
<subfield code="a">k</subfield>
</datafield>
<datafield1 tag="245" ind1=" " ind2=" ">
<subfield code="a">k</subfield>
</datafield>
<datafield1 tag="250" ind1=" " ind2=" ">
<subfield code="a">k</subfield>
</datafield>
<datafield1 tag="260" ind1=" " ind2=" ">
<subfield code="b">k</subfield>
<subfield code="c">k</subfield>
</datafield>
</datafield>
</record>
</collection>

Which will result later in the following error:
:23: parser error : Opening and ending tag mismatch: record line 6 and datafield
</datafield>
            ^
:24: parser error : Opening and ending tag mismatch: collection line 2 and record
</record>
         ^
:25: parser error : Extra content at the end of the document
</collection>

Test plan:
You can test it along with bug 19289 and confirm that it fixes the problem
raised on bug 19289 comment 30

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
C4/Biblio.pm
t/Biblio/TransformHtmlToXml.t

index 91707fd..5749bba 100644 (file)
@@ -2263,6 +2263,7 @@ sub TransformHtmlToXml {
     my $prevtag = -1;
     my $first   = 1;
     my $j       = -1;
+    my $close_last_tag;
     for ( my $i = 0 ; $i < @$tags ; $i++ ) {
 
         if ( C4::Context->preference('marcflavour') eq 'UNIMARC' and @$tags[$i] eq "100" and @$subfields[$i] eq "a" ) {
@@ -2283,6 +2284,7 @@ sub TransformHtmlToXml {
         @$values[$i] =~ s/'/&apos;/g;
 
         if ( ( @$tags[$i] ne $prevtag ) ) {
+            $close_last_tag = 0;
             $j++ unless ( @$tags[$i] eq "" );
             my $indicator1 = eval { substr( @$indicator[$j], 0, 1 ) };
             my $indicator2 = eval { substr( @$indicator[$j], 1, 1 ) };
@@ -2301,6 +2303,7 @@ sub TransformHtmlToXml {
                     $xml .= "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
                     $xml .= "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
                     $first = 0;
+                    $close_last_tag = 1;
                 } else {
                     $first = 1;
                 }
@@ -2320,6 +2323,7 @@ sub TransformHtmlToXml {
                         $xml .= "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
                         $xml .= "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
                         $first = 0;
+                        $close_last_tag = 1;
                     }
                 }
             }
@@ -2339,13 +2343,14 @@ sub TransformHtmlToXml {
                 if ($first) {
                     $xml .= "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
                     $first = 0;
+                    $close_last_tag = 1;
                 }
                 $xml .= "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
             }
         }
         $prevtag = @$tags[$i];
     }
-    $xml .= "</datafield>\n" if $xml =~ m/<datafield/;
+    $xml .= "</datafield>\n" if $close_last_tag;
     if ( C4::Context->preference('marcflavour') eq 'UNIMARC' and !$unimarc_and_100_exist ) {
 
         #     warn "SETTING 100 for $auth_type";
@@ -2362,6 +2367,7 @@ sub TransformHtmlToXml {
     }
     $xml .= "</record>\n";
     $xml .= MARC::File::XML::footer();
+    use Data::Printer colored => 1; warn p $xml;
     return $xml;
 }
 
index c95c120..bbbadd2 100644 (file)
@@ -33,14 +33,14 @@ sub run_tests {
 
     my ( $tags, $subfields );
     if ( $marc_flavour eq 'UNIMARC' ) {
-        $tags= [ '001', '600',  '200', '200' ];
-        $subfields = [ '', 'a', 'a', 'c' ];
+        $tags= [ '001', '600',  '200', '200', '400' ];
+        $subfields = [ '', 'a', 'a', 'c', 'a' ];
     } else {
-        $tags= [ '001', '100',  '245', '245' ];
-        $subfields = [ '', 'a', 'a', 'c' ];
+        $tags= [ '001', '100',  '245', '245', '400' ];
+        $subfields = [ '', 'a', 'a', 'c', 'a' ];
     }
-    my $values = [ '12345', 'author', 'title', 'resp' ];
-    my $ind = [ '  ', '00', ' 9', '  ' ];
+    my $values = [ '12345', 'author', 'title', 'resp', '' ];
+    my $ind = [ '  ', '00', ' 9', '  ', ' ' ];
 
     my $xml = TransformHtmlToXml( $tags, $subfields, $values, $ind, undef, $marc_flavour );
     my $xmlh = XML::Simple->new->XMLin( $xml );