#!/usr/bin/perl

=Instructions

svg-sieve  [-d ma|mi|all] [-i]   l- name[,name]...  [filename.svg]

This program helps displaying only selected groups/layers of an SVG file.
Select a top level group if its ID or layer name is BASE-* or is in the name list.
Enforce its visibility (style="display:inline") and write it to standard output.
Weed out (skip) the unwanted, other top level groups.
Also write the rest.
Ideas and code are a Public Domain contribution by André Pirard, in thanks to all.
Status: Operational, can be used on a test basis, improvements possible.
Support Inkscape layer names and any program/method to set a group ID name.
Any idiom that sets an attribute of those groups can be supported.
Possible technical improvements: using start_tag_handlers.

The sieved SVG data comes from:
- a file if filename.svg is present
- standard input pipe (|))
- an example in the program code with l- default otherwise
and it goes to standard output.

Usage: group optional or alternative SVG element sets in layers.
Name each layer such as language=fr, Cyrillic_keys, except_local_traffic, rivers, etc...
Special case: languages: duplicate a language=xx layer, rename it, translate it.
Use command: svg_producer | svg-sieve mychoice1,mychoice2,... | svg-consumer
example: cat in.svg | svg-sieve -l language=fr,London | rsvg-convert > out.png
Method:
Presently, only Inkscape layers (non-inner SVG groups) and IDs are examined,
whose parent is not a group and with an attribute inkscape:label= or id=  "name".
Unexamined SVG elements, are kept unchanged (flushed).
If the layer name (value is in the name list), visibility is forced (style=display:inline).
Otherwise, the layer (whole group) is removed from the data stream (purged).

=cut

use feature 'unicode_strings';                  
use open qw(:std :utf8);                          
use utf8;
use XML::Twig;
use Getopt::Std;
use File::Basename;

$cmdname=basename($0);

sub usage() { print STDERR << "FIN DES HARICOTS";

This program helps displaying only selected groups/layers of an SVG file.
See details in code.

usage:  $cmdname [-d] -l match[,match]...

 -h                : (or whatever you typed) displays this help
 -d ma|mi|all      : print match|miss|all debugging messages to stderr
 -l name[,name]... : names of layers to display to select
 -i                : indent the output

example: $cmdname -d -l layer1,layer2  file
Standard output contains a visiility modified SVG.
Self-test with no parameters except -d all

FIN DES HARICOTS
    exit;
}

my %options=("l","additional,language=ru,should disregard"); # internal test
getopts("d:l:i", \%options) or usage();
my @matchlist = split(",", $options{l});
!$options{i} or my $indent='indented';
my $debug = $options{d};
if ($debug) {
  if    ($debug =~ /^ma/) { $debugma=1; }
  elsif ($debug =~ /^mi/) { $debugmi=1; }
  else                    { $debugma=1; $debugmi=1; }
}

my $twig = new XML::Twig( twig_roots => { 'g' => \&g },
           twig_print_outside_roots => 1, pretty_print => "$indent",);

sub g { my ($t, $g) = @_; 
  return if $g->parent->gi eq "g";
  my $label=$g->att("inkscape:label");
  $label or $label=$g->att("id");
  if ( $label ~~ @matchlist | $label =~ /^BASE-/) {
!$debugma or print STDERR "match ", $label, "  ", $g->parent->gi, "\n";
    my $style=$g->att("style");
    $style =~ s/display:[^;]*(;?)/display:inline\1/;
    $g->set_att( style => "$style");
    $g-> flush;
  } else {
!$debugmi or print STDERR "miss  ", $label, "\n";
    $g-> purge;
  }
}

if( $ARGV[0])      { $twig->parsefile( $ARGV[0]); }	# parse a file
elsif (! -t STDIN) { $twig->parse( \*STDIN);      }	# parse a data pipe
else { my $xml = <<'FIN DU MONDE';			# inline example, no SVG typing ;-)
<svg>
  <stuff1 />
  <g inkscape:label="additional"  style="visibility:visible;display:none" > stuff here </g>
  <stuff2 />
  <g inkscape:label="language=en" style="visibility:visible;display:inline" > stuff here </g>
  <stuff3 />
  <g inkscape:label="language=fr" style="visibility:visible;display:none" > stuff here 
     <g inkscape:label="should disregard"> </g> </g>
  <g inkscape:label="language=ru" style="visibility:visible;display:none" > plenty of other
      <stuff> like this </stuff>
     <g inkscape:label="should disregard"> </g> 
  </g>
<!-- id test -->
  <stuff1 />
  <g id="language=fr" style="visibility:visible;display:none" > stuff here 
     <g id="should disregard"> </g> </g>
  <g id="language=ru" style="visibility:visible;display:none" > plenty of other
      <stuff> like this </stuff>
     <g id="should disregard"> </g> 
  </g>
</svg>
FIN DU MONDE
  $twig->parse( $xml );
}
$twig->flush; 



