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