View Javadoc
1   package org.djunits.generator;
2   
3   import java.io.BufferedReader;
4   import java.io.File;
5   import java.io.FileNotFoundException;
6   import java.io.FileReader;
7   import java.io.PrintWriter;
8   import java.net.URISyntaxException;
9   import java.net.URL;
10  
11  /**
12   * GenerateXSD makes an XSD file for all choices possible with the units, using the textual representations. <br>
13   * <br>
14   * Copyright (c) 2003-2018 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
15   * for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
16   * source code and binary code of this software is proprietary information of Delft University of Technology.
17   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
18   */
19  public class GenerateXSD
20  {
21      /** The output folder of the writer -- will be written in Eclipse project-root/generated-code/org/djunits folder. */
22      private static final String generatedCodeRelativePath = "/generated-code/";
23  
24      /**
25       * The calculated absolute output path (root of the executable or Jar file). In case of an Eclipse run, ../../ is added to
26       * the path to place the results in the root of the project, rather than in target/classes.
27       */
28      private static String absoluteRootPath;
29  
30      /*-
31       * DurationUnit.ms = ms  | millisecond
32         DurationUnit.s  = s   | second
33         DurationUnit.m  = min | minute | min | m
34       */
35  
36      /**
37       * @param args String[]; not used
38       * @throws FileNotFoundException in case we cannot find the djunits project
39       */
40      public static void main(final String[] args) throws FileNotFoundException
41      {
42          makeAbsolutePath();
43          makeXsd();
44          // makeAdapters();
45      }
46  
47      /** */
48      private static void makeXsd()
49      {
50          try
51          {
52              File in = new File(absoluteRootPath + "../../djunits/src/main/resources/localeunit.properties");
53              if (!in.exists())
54              {
55                  throw new RuntimeException("cannot find file " + in.getPath());
56              }
57              BufferedReader br = new BufferedReader(new FileReader(in));
58  
59              File outPath = new File(absoluteRootPath + "/resources");
60              outPath.mkdirs();
61              PrintWriter pw = new PrintWriter(absoluteRootPath + "/resources/djunits.xsd");
62              pw.write(
63                      "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <xsd:schema targetNamespace=\"http://www.djunits.org/djunits\"\n");
64              pw.write("  xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n");
65              pw.write("  xmlns:djunits=\"http://www.djunits.org/djunits\"\n");
66              pw.write("  xmlns=\"http://www.djunits.org/djunits\" elementFormDefault=\"qualified\">\n");
67              pw.write("\n");
68              pw.write("  <!-- ========================================================================================= -->\n");
69              pw.write("  <!-- ==================================== DJUNITS UNIT TYPES ================================= -->\n");
70              pw.write("  <!-- ========================================================================================= -->\n");
71              pw.write("\n");
72  
73              String typeStr = "";
74              String line = br.readLine();
75              while (line != null)
76              {
77                  if (line.startsWith("#"))
78                  {
79                      line = br.readLine();
80                      continue;
81                  }
82  
83                  if (line.contains("="))
84                  {
85                      typeStr = writeType(pw, line, typeStr);
86                  }
87                  line = br.readLine();
88              }
89  
90              if (typeStr.length() > 0)
91              {
92                  pw.write(")\"></xsd:pattern>\n" + "    </xsd:restriction>\n" + "  </xsd:simpleType>\n\n");
93              }
94  
95              pw.write("  <!-- ========================================================================================= -->\n");
96              pw.write("  <!-- ================================== DJUNITS SCALAR TYPES ================================= -->\n");
97              pw.write("  <!-- ========================================================================================= -->\n");
98              pw.write("\n");
99  
100             br.close();
101             br = new BufferedReader(new FileReader(in));
102             typeStr = "";
103             line = br.readLine();
104             while (line != null)
105             {
106                 if (line.startsWith("#"))
107                 {
108                     line = br.readLine();
109                     continue;
110                 }
111 
112                 if (line.contains("="))
113                 {
114                     typeStr = writeScalar(pw, line, typeStr, false);
115                 }
116                 line = br.readLine();
117             }
118 
119             if (typeStr.length() > 0)
120             {
121                 pw.write(")\"></xsd:pattern>\n" + "    </xsd:restriction>\n" + "  </xsd:simpleType>\n\n");
122             }
123 
124             pw.write("  <!-- ========================================================================================= -->\n");
125             pw.write("  <!-- ============================= DJUNITS POSITIVE SCALAR TYPES ============================= -->\n");
126             pw.write("  <!-- ========================================================================================= -->\n");
127             pw.write("\n");
128 
129             br.close();
130             br = new BufferedReader(new FileReader(in));
131             typeStr = "";
132             line = br.readLine();
133             while (line != null)
134             {
135                 if (line.startsWith("#"))
136                 {
137                     line = br.readLine();
138                     continue;
139                 }
140 
141                 if (line.contains("="))
142                 {
143                     typeStr = writeScalar(pw, line, typeStr, true);
144                 }
145                 line = br.readLine();
146             }
147 
148             if (typeStr.length() > 0)
149             {
150                 pw.write(")\"></xsd:pattern>\n" + "    </xsd:restriction>\n" + "  </xsd:simpleType>\n\n" + "</xsd:schema>\n");
151             }
152             pw.close();
153             br.close();
154 
155             System.out.println("built: " + absoluteRootPath + "/resources/djunits.xsd");
156 
157         }
158         catch (Exception exception)
159         {
160             exception.printStackTrace();
161         }
162     }
163 
164     /**
165      * Write a scalar with unit to the file, with or without [+-]?
166      * @param pw the file to write to
167      * @param typeStrOrig the previous the unit we were looking at
168      * @param line the line from the preoperties file
169      * @param plus with or without [+-]?
170      * @return the unit we are looking at
171      */
172     private static String writeScalar(final PrintWriter pw, final String line, final String typeStrOrig, final boolean plus)
173     {
174         /*-
175         <xsd:simpleType name="SPEEDTYPE"> 
176           <xsd:restriction base="xsd:string">
177             <xsd:pattern value="\d+\.?\d*\s*(km/h|m/s|mi/h|ft/s)"></xsd:pattern>
178           </xsd:restriction>
179         </xsd:simpleType>
180         */
181 
182         if (line.startsWith("Money") || line.startsWith("Dimension"))
183         {
184             return typeStrOrig;
185         }
186 
187         String typeStr = typeStrOrig;
188         String key = line.split("=")[0].trim().split("\\.")[0];
189         String val = line.split("=")[1].trim();
190         String[] vals = val.split("\\|");
191         if (!typeStr.equals(key))
192         {
193             // new type
194             if (typeStr.length() > 0)
195             {
196                 if (typeStr.startsWith("Dimension"))
197                     pw.write("\"></xsd:pattern>\n" + "    </xsd:restriction>\n" + "  </xsd:simpleType>\n\n");
198                 else
199                     pw.write(")\"></xsd:pattern>\n" + "    </xsd:restriction>\n" + "  </xsd:simpleType>\n\n");
200             }
201             typeStr = key;
202             String type = key.replace("Unit", "TYPE").toUpperCase();
203             if (plus)
204             {
205                 type = "POSITIVE" + type;
206             }
207             pw.write("  <xsd:simpleType name=\"" + type + "\">\n");
208             pw.write("     <xsd:restriction base=\"xsd:string\">\n");
209             String plusmin = plus ? "" : "[+-]?";
210             if (type.contains("DIMENSIONLESS"))
211                 pw.write("      <xsd:pattern value=\"" + plusmin + "[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?\\s*");
212             else
213             {
214                 pw.write("      <xsd:pattern value=\"" + plusmin + "[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?\\s*(");
215                 if (vals.length > 2)
216                 {
217                     pw.write(escape(vals[2]));
218                     for (int i = 3; i < vals.length; i++)
219                         pw.write("|" + escape(vals[i]));
220                 }
221                 else
222                 {
223                     pw.write(escape(vals[0]));
224                 }
225             }
226         }
227         else
228         {
229             if (vals.length > 2)
230             {
231                 for (int i = 2; i < vals.length; i++)
232                     pw.write("|" + escape(vals[i]));
233             }
234             else
235             {
236                 pw.write("|" + escape(vals[0]));
237             }
238         }
239         System.out.println(vals[0]);
240         return typeStr;
241     }
242 
243     /**
244      * Write a unit type to the file
245      * @param pw the file to write to
246      * @param typeStrOrig the previous the unit we were looking at
247      * @param line the line from the preoperties file
248      * @return the unit we are looking at
249      */
250     private static String writeType(final PrintWriter pw, final String line, final String typeStrOrig)
251     {
252         /*-
253           <xsd:simpleType name="SPEEDUNITTYPE">
254             <xsd:restriction base="xsd:string">
255               <xsd:pattern value="(m/s|km/h|mi/h|ft/s|kt|m/h|km/s|mi/min|in/min|ft/min|ft/h|mi/s|in/h|in/s)"></xsd:pattern>
256             </xsd:restriction>
257           </xsd:simpleType>
258         */
259 
260         if (line.startsWith("Money") || line.startsWith("Dimension"))
261         {
262             return typeStrOrig;
263         }
264 
265         String typeStr = typeStrOrig;
266         String key = line.split("=")[0].trim().split("\\.")[0];
267         String val = line.split("=")[1].trim();
268         String[] vals = val.split("\\|");
269         if (!typeStr.equals(key))
270         {
271             // new type
272             if (typeStr.length() > 0)
273             {
274                 pw.write(")\"></xsd:pattern>\n" + "    </xsd:restriction>\n" + "  </xsd:simpleType>\n\n");
275             }
276             typeStr = key;
277             String type = key.replace("Unit", "UNITTYPE").toUpperCase();
278             pw.write("  <xsd:simpleType name=\"" + type + "\">\n");
279             pw.write("     <xsd:restriction base=\"xsd:string\">\n");
280             pw.write("      <xsd:pattern value=\"(");
281             if (vals.length > 2)
282             {
283                 pw.write(escape(vals[2]));
284                 for (int i = 3; i < vals.length; i++)
285                     pw.write("|" + escape(vals[i]));
286             }
287             else
288             {
289                 pw.write(escape(vals[0]));
290             }
291         }
292         else
293         {
294             if (vals.length > 2)
295             {
296                 for (int i = 2; i < vals.length; i++)
297                     pw.write("|" + escape(vals[i]));
298             }
299             else
300             {
301                 pw.write("|" + escape(vals[0]));
302             }
303         }
304         System.out.println(vals[0]);
305         return typeStr;
306     }
307 
308     /** the characters to escape. */
309     private static final String escape = "(){}.?|<>*-+'\\%^";
310 
311     /**
312      * @param s the String to escape
313      * @return the String with \ before escaped chars
314      */
315     private static String escape(String s)
316     {
317         String out = "";
318         for (char c : s.toCharArray())
319         {
320             if (escape.indexOf(c) >= 0)
321                 out += "\\";
322             if (c == '"')
323                 out += "&quot;";
324             else
325                 out += c;
326         }
327         return out.trim();
328     }
329 
330     /**
331      * Determine calculated absolute output path (root of the executable or Jar file). In case of an Eclipse run, ../../ is
332      * added to the path to place the results in the root of the project, rather than in target/classes.<br>
333      * See https://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html and
334      * http://stackoverflow.com/questions/320542/how-to-get-the-path-of-a-running-jar-file and
335      * http://stackoverflow.com/questions/3153337/get-current-working-directory-in-java
336      * @throws FileNotFoundException in case file could not be found
337      */
338     private static void makeAbsolutePath() throws FileNotFoundException
339     {
340         URL mainURL = URLResource.getResource("/");
341         String path;
342         try
343         {
344             path = mainURL.toURI().getPath();
345         }
346         catch (URISyntaxException exception)
347         {
348             path = mainURL.getPath();
349         }
350         if (path.endsWith("/target/classes/"))
351         {
352             path = path.substring(0, path.length() - "/target/classes/".length());
353         }
354         path += generatedCodeRelativePath;
355         if (!new File(path).exists())
356         {
357             new File(path).mkdirs();
358         }
359         absoluteRootPath = path;
360         System.out.println("writing into: " + path);
361     }
362 }