2 # Heavily revised Jan-2010 <seligman@nevis.columbia.edu>
5 # Build a description of the detectors from gdml fragments
8 # Use the command line arguments to give us the list of file fragments
9 # that we'll zip together. The man page for 'GetOptions' can be read
10 # with: perldoc Getopt::Long
13 GetOptions( "input|i:s" => \$input,
15 "output|o:s" => \$output);
19 # If the user requested help, print the usage notes and exit.
24 if ( ! defined $input )
26 # If the user has not used "-i", then just take the first
27 # non-option argument.
33 print "Input file $input not found\n";
46 # The "-i" option was provided; check that the input file exists.
49 print "Input file $input not found or cannot be read\n";
55 if ( ! defined $output )
57 $output = "-"; # write to STDOUT
60 # Read the list of file fragments from an XML-formatted file.
61 # (Type "perldoc XML::LibXML" for how to use this package.)
64 # Create an XML parser.
65 $parser = new XML::LibXML;
67 # Read the XML file. The entire contents are slurped into a DOM
69 $dom = $parser->parse_file($input);
71 # Note that @defFiles and @gdmlFiles are both arrays of "nodes".
72 @defFiles = $dom->findnodes('/config/constantfiles/filename');
73 @gdmlFiles = $dom->findnodes('/config/gdmlfiles/filename');
75 # Keep track of how many constants we read in.
76 $numberConstants = -1;
78 # Developer note: If I were slicker, I'd also use XML::LibXML to read
79 # in these GDML fragments. However, the files would have to be edited
80 # to be strict XML, and that's more effort than it's worth. The script
81 # generate_gdml.pl writes strict XML documents, but there's no
82 # guarantee that this program will be used just with those
86 # Build the table of variable replacements
89 # For each node that represents a file of constants...
90 foreach $filename (@defFiles)
92 $CONSTANTS = $filename->to_literal;
93 open(CONSTANTS) or die("Could not open file $CONSTANTS");
95 # For each line in the file...
96 foreach $line (<CONSTANTS>)
98 # Find the name and value as defined in a <constant> block; e.g.:
99 # <constant name="kInch" value="2.54" />
100 # will be parsed as $name="kInch" and value = "2.54"
102 # If the line begins with "<constant"...
103 if ( $line =~ /^\s*<constant / )
105 # (See "perldoc perlfaq6" for the definition of a non-greedy search.)
106 # Do a "non-greedy" search to get the text assigned to 'name'
107 $line =~ /name="(.*?)"/;
109 # Do a "non-greedy" search to get the text assigned to 'value'
110 $line =~ /value="(.*?)"/;
113 # Append to the list of constants. Put parenthesis around
114 # the value, to avoid potential problems with arithmetic.
116 $name[$numberConstants] = $name;
117 $value[$numberConstants] = "($value)";
118 # print "$numberConstants: $name = $value[$numberConstants]\n"; # debug
124 # The main GDML keywords, used in tags. The order here is important:
125 # No matter what order these blocks are in the sub-files, this is the
126 # order in which they must be written in the final GDML output.
128 # If I were being super-slick, I'd use the features of LibXML to read
129 # each of these GDML sub-files, then fiddle with the elements using
130 # XML manipulation routines. However, it's much simpler to treat them
131 # as big globs of text.
133 @keywords = qw( extension define materials solids structure );
135 # For each node that's a file of GDML statements...
136 foreach $filename ( @gdmlFiles )
140 $FILE = $filename->to_literal;
141 open(FILE) or die("Could not open file $FILE for read.");
143 # Read the entire file into an array.
147 # Slurp the array into a single variable.
148 $file = join("",@file);
150 foreach $keyword ( @keywords )
152 # Search the file for a keyword block. For example, if
153 # $keyword were "blorg", the following would search for
154 # <blorg>some text</blorg> and snip it out of $file.
155 while ( $file =~ s/(.*)<$keyword>(.*?)<\/$keyword>(.*)/\1\3/s )
157 # Following the above example, this would append "some
158 # text" to $keyhash{blorg}
160 $keyhash{$keyword} = $keyhash{$keyword} . $2;
165 # Write the final GDML file.
167 $OUTPUT = ">" . $output;
168 open(OUTPUT) or die("Could not open $output for writing");
170 # The preliminary material for the GDML file. This defines the GDML
171 # schema and namespaces.
174 <?xml version="1.0" encoding="UTF-8" ?>
175 <gdml_simple_extension xmlns:gdml_simple_extension="http://www.example.org"
176 xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
177 xs:noNamespaceSchemaLocation="RefactoredGDMLSchema/SimpleExtension.xsd">
181 # Print to OUTPUT all the GDML sections, with each set of tags
182 # unified, in the appropriate order.
184 foreach $keyword ( @keywords )
186 print OUTPUT "<$keyword>";
188 # Substitute any constants in the GDML with their numeric
191 # In strict GDML, this should not be necessary; according to the
192 # specification, you should be able to define a constant and use
193 # it in subsequent GDML statements. If you use the standard GDML
194 # parser, this not a problem. ROOT, however, uses its own parser,
195 # and (as of ROOT 5.16) it could not handle variables in GDML
196 # expressions. So here we side-step the problem by performing our
199 # Step through this list of constants in reverse order, to resolve
202 for ( $i = $numberConstants; $i >= 0; --$i )
204 $keyhash{$keyword} =~ s/$name[$i]/$value[$i]/g;
207 # Print the edited section.
208 print OUTPUT $keyhash{$keyword};
210 print OUTPUT "</$keyword>\n";
213 # The final section of a GDML file is the <setup></setup> section. At
214 # present, we don't define alternate setups in the same GDML file, so
215 # these lines are constant.
219 <setup name="Default" version="1.0">
220 <world ref="volWorld"/>
223 </gdml_simple_extension>
231 print "Usage: $0 [-h|--help] [-i|--input <xml-fragments-file>] [-o|--output <output-file>]\n";
232 print " -i/--input can be omitted; if no input file, defaults to STDIN\n";
233 print " if -o is omitted, output goes to STDOUT\n";
234 print " -h prints this message, then quits\n";