xml2lst.pl revision 154daed1
1#!/usr/bin/perl
2
3# converts the <rules>.xml file to the old format <rules>.lst file
4#
5# Usage:
6#
7# perl xml2lst.pl [lang] < filename.xml > filename.lst
8#
9# author Ivan Pascal
10
11if (@ARGV) {
12   $lang = shift @ARGV;
13} else {
14   $lang = '';
15}
16
17$doc = new_document( 0, '');
18parse('', $doc);
19
20($reg)   = node_by_name($doc, '/xkbConfigRegistry');
21@models  = node_by_name($reg, 'modelList/model/configItem');
22@layouts = node_by_name($reg, 'layoutList/layout/configItem');
23@options = node_by_name($reg, 'optionList/group/configItem');
24
25print "! model\n";
26for $i (@models) {
27   ($name) = node_by_name($i, 'name');
28    @desc =  node_by_name($i, 'description');
29    $descr = with_attribute(\@desc, 'xml:lang='.$lang);
30    if (! defined $descr) {
31        $descr = with_attribute(\@desc, 'xml:lang=');
32    }
33    printf("  %-15s %s\n", text_child($name), text_child($descr));
34}
35
36print "\n! layout\n";
37for $i (@layouts) {
38   ($name) = node_by_name($i, 'name');
39    @desc =  node_by_name($i, 'description');
40    $descr = with_attribute(\@desc, 'xml:lang='.$lang);
41    if (! defined $descr ) {
42        $descr = with_attribute(\@desc, 'xml:lang=');
43    }
44    printf("  %-15s %s\n", text_child($name), text_child($descr));
45}
46
47print "\n! variant\n";
48for $l (@layouts) {
49   ($lname) = node_by_name($l, 'name');
50    @variants = node_by_name($l, '../variantList/variant/configItem');
51    for $v (@variants) {
52      ($name) = node_by_name($v, 'name');
53       @desc  = node_by_name($v, 'description');
54       $descr = with_attribute(\@desc, 'xml:lang='.$lang);
55       if (! defined $descr) {
56           $descr = with_attribute(\@desc, 'xml:lang=');
57       }
58       printf("  %-15s %s: %s\n",
59               text_child($name), text_child($lname), text_child($descr));
60    }
61}
62
63print "\n! option\n";
64for $g (@options) {
65   ($name) = node_by_name($g, 'name');
66    @desc =  node_by_name($g, 'description');
67    $descr = with_attribute(\@desc, 'xml:lang='.$lang);
68    if (! defined $descr) {
69        $descr = with_attribute(\@desc, 'xml:lang=');
70    }
71    printf("  %-20s %s\n", text_child($name), text_child($descr));
72
73    @opts = node_by_name($g, '../option/configItem');
74    for $o (@opts) {
75      ($name) = node_by_name($o, 'name');
76       @desc  = node_by_name($o, 'description');
77       $descr = with_attribute(\@desc, 'xml:lang='.$lang);
78       if (! defined $descr) {
79           $descr = with_attribute(\@desc, 'xml:lang=');
80       }
81       printf("  %-20s %s\n",
82               text_child($name), text_child($descr));
83    }
84}
85
86sub with_attribute {
87    local ($nodelist, $attrexpr) = @_;
88    local ($attr, $value) = split (/=/, $attrexpr);
89    local ($node, $attrvalue);
90    if (defined $value && $value ne '') {
91        $value =~ s/"//g;
92        foreach $node (@{$nodelist}) {
93           $attrvalue = node_attribute($node, $attr);
94           if (defined $attrvalue && $attrvalue eq $value) {
95               return $node;
96           }
97        }
98    } else {
99        foreach $node (@{$nodelist}) {
100           if (! defined node_attribute($node, $attr)) {
101               return $node;
102           }
103        }
104    }
105    undef;
106}
107
108# Subroutines
109
110sub parse {
111   local $intag = 0;
112   my (@node_stack, $parent);
113   $parent = @_[1];
114   local ($tag, $text);
115
116   while (<>) {
117      chomp;
118      @str = split /([<>])/;
119      shift @str if ($str[0] eq '' || $str[0] =~ /^[ \t]*$/);
120
121      while (scalar @str) {
122         $token = shift @str;
123         if ($token eq '<') {
124            $intag = 1;
125            if (defined $text) {
126               add_text_node($parent, $text);
127               undef $text;
128            }
129         } elsif ($token eq '>') {
130            $intag = 0;
131            if ($tag =~ /^\/(.*)/) { # close tag
132               $parent = pop @node_stack;
133            } elsif ($tag =~ /^([^\/]*)\/$/) {
134               empty_tag($parent, $1);
135            } else {
136               if (defined ($node = open_tag($parent, $tag))) {
137                  push @node_stack, $parent;
138                  $parent = $node;
139               }
140            }
141            undef $tag;
142         } else {
143            if ($intag == 1) {
144               if (defined $tag) {
145                  $tag .= ' '. $token;
146               } else {
147                  $tag = $token;
148               }
149            } else {
150               if (defined $text) {
151                  $text .= "\n" . $token;
152               } else {
153                  $text = $token;
154               }
155            }
156         }
157      }
158   }
159}
160
161sub new_document {
162   $doc = new_node( 0, '', 'DOCUMENT');
163   $doc->{CHILDREN} = [];
164   return $doc;
165}
166
167sub new_node {
168  local ($parent_node, $tag, $type) = @_;
169
170  my %node;
171  $node{PARENT} = $parent_node;
172  $node{TYPE} = $type;
173
174  if ($type eq 'COMMENT' || $type eq 'TEXT') {
175     $node{TEXT} = $tag;
176     $node{NAME} = $type;
177     return \%node;
178  }
179
180  local ($tname, $attr) = split(' ', $tag, 2);
181  $node{NAME} = $tname;
182
183  if (defined $attr && $attr ne '') {
184     my %attr_table;
185     local @attr_list = split ( /"/, $attr);
186     local ($name, $value);
187     while (scalar @attr_list) {
188        $name = shift @attr_list;
189        $name =~ s/[ =]//g;
190        next if ($name eq '');
191        $value =  shift @attr_list;
192        $attr_table{$name} =$value;
193     }
194     $node{ATTRIBUTES} = \%attr_table;
195  }
196  return \%node;
197}
198
199sub add_node {
200  local ($parent_node, $node) = @_;
201  push @{$parent_node->{CHILDREN}}, $node;
202
203  local $tname = $node->{NAME};
204  if (defined $parent_node->{$tname}) {
205      push @{$parent_node->{$tname}}, $node
206  } else {
207      $parent_node->{$tname} = [ $node ];
208  }
209}
210
211sub empty_tag {
212   local ($parent_node, $tag) = @_;
213   local $node = new_node($parent_node, $tag, 'EMPTY');
214   add_node($parent_node, $node);
215}
216
217sub open_tag {
218   local ($parent_node, $tag) = @_;
219   local $node;
220
221   if ($tag =~ /^\?.*/ || $tag =~ /^\!.*/) {
222      $node = new_node($parent_node, $tag, 'COMMENT');
223      add_node($parent_node, $node);
224      undef; return;
225   } else {
226      $node = new_node($parent_node, $tag, 'NODE');
227      $node->{CHILDREN} = [];
228      add_node($parent_node, $node);
229      return $node;
230   }
231}
232
233sub add_text_node {
234   local ($parent_node, $text) = @_;
235   local $node = new_node($parent_node, $text, 'TEXT');
236   add_node($parent_node, $node);
237}
238
239sub node_by_name {
240   local ($node, $name) = @_;
241   local ($tagname, $path) = split(/\//, $name, 2);
242
243   my @nodelist;
244
245   if ($tagname eq '') {
246      while ($node->{PARENT} != 0) {
247         $node = $node->{PARENT};
248      }
249      sublist_by_name($node, $path, \@nodelist);
250   } else {
251      sublist_by_name($node, $name, \@nodelist);
252   }
253   return @nodelist;
254}
255
256sub sublist_by_name {
257   local ($node, $name, $res) = @_;
258   local ($tagname, $path) = split(/\//, $name, 2);
259
260   if (! defined $path) {
261       push @{$res}, (@{$node->{$tagname}});
262       return;
263   }
264
265   if ($tagname eq '..' && $node->{PARENT} != 0) {
266      $node = $node->{PARENT};
267      sublist_by_name($node, $path, $res);
268   } else {
269      local $n;
270      for $n (@{$node->{$tagname}}) {
271         sublist_by_name($n, $path, $res);
272      }
273   }
274}
275
276sub node_attribute {
277    local $node = @_[0];
278    if (defined $node->{ATTRIBUTES}) {
279       return $node->{ATTRIBUTES}{@_[1]};
280    }
281    undef;
282}
283
284sub text_child {
285    local ($node) = @_;
286    local ($child) = node_by_name($node, 'TEXT');
287    return $child->{TEXT};
288}
289