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     /** indicate first unit, so no |. */
159     static boolean first;
160      
161     /**
162      * Write a scalar with unit to the file, with or without [+-]?
163      * @param pw PrintWriter; the file to write to
164      * @param typeStrOrig String; the previous the unit we were looking at
165      * @param line String; the line from the preoperties file
166      * @param plus boolean; with or without [+-]?
167      * @return the unit we are looking at
168      */
169     private static String writeScalar(final PrintWriter pw, final String line, final String typeStrOrig, final boolean plus)
170     {
171         /*-
172         <xsd:simpleType name="SPEEDTYPE"> 
173           <xsd:restriction base="xsd:string">
174             <xsd:pattern value="\d+\.?\d*\s*(km/h|m/s|mi/h|ft/s)"></xsd:pattern>
175           </xsd:restriction>
176         </xsd:simpleType>
177         */
178 
179         if (line.startsWith("Dimension"))
180         {
181             return typeStrOrig;
182         }
183 
184         String typeStr = typeStrOrig;
185         String key = line.split("=")[0].trim().split("\\.")[0];
186         String val = line.split("=")[1].trim();
187         String[] vals = val.split("\\|");
188         if (!typeStr.equals(key))
189         {
190             // new type
191             if (typeStr.length() > 0)
192             {
193                 if (typeStr.startsWith("Dimension"))
194                     pw.write("\"></xsd:pattern>\n" + "    </xsd:restriction>\n" + "  </xsd:simpleType>\n\n");
195                 else
196                     pw.write(")\"></xsd:pattern>\n" + "    </xsd:restriction>\n" + "  </xsd:simpleType>\n\n");
197             }
198             typeStr = key;
199             String type = key.toUpperCase() + "TYPE";
200             if (plus)
201             {
202                 type = "POSITIVE" + type;
203             }
204             pw.write("  <xsd:simpleType name=\"" + type + "\">\n");
205             pw.write("     <xsd:restriction base=\"xsd:string\">\n");
206             String plusmin = plus ? "" : "[+-]?";
207             if (type.contains("DIMENSIONLESS"))
208                 pw.write("      <xsd:pattern value=\"" + plusmin + "[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?\\s*");
209             else
210                 pw.write("      <xsd:pattern value=\"" + plusmin + "[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?\\s*(");
211             first = true;
212         }
213         else
214         {
215             if (!first)
216                 pw.write("|");
217             first = false;
218             pw.write(escape(vals[0]));
219             for (int i = 2; i < vals.length; i++)
220                 pw.write("|" + escape(vals[i]));
221         }
222         System.out.println(vals[0]);
223         return typeStr;
224     }
225 
226     /**
227      * Write a unit type to the file
228      * @param pw PrintWriter; the file to write to
229      * @param typeStrOrig String; the previous the unit we were looking at
230      * @param line String; the line from the preoperties file
231      * @return the unit we are looking at
232      */
233     private static String writeType(final PrintWriter pw, final String line, final String typeStrOrig)
234     {
235         /*-
236           <xsd:simpleType name="SPEEDUNITTYPE">
237             <xsd:restriction base="xsd:string">
238               <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>
239             </xsd:restriction>
240           </xsd:simpleType>
241         */
242 
243         if (line.startsWith("Dimension"))
244         {
245             return typeStrOrig;
246         }
247 
248         String typeStr = typeStrOrig;
249         String key = line.split("=")[0].trim().split("\\.")[0];
250         String val = line.split("=")[1].trim();
251         String[] vals = val.split("\\|");
252         if (!typeStr.equals(key))
253         {
254             // new type
255             if (typeStr.length() > 0)
256             {
257                 pw.write(")\"></xsd:pattern>\n" + "    </xsd:restriction>\n" + "  </xsd:simpleType>\n\n");
258             }
259             typeStr = key;
260             String type = key.toUpperCase() + "UNITTYPE";
261             pw.write("  <xsd:simpleType name=\"" + type + "\">\n");
262             pw.write("     <xsd:restriction base=\"xsd:string\">\n");
263             pw.write("      <xsd:pattern value=\"(");
264             first = true;
265         }
266         else
267         {
268             if (!first)
269                 pw.write("|");
270             first = false;
271             pw.write(escape(vals[0]));
272             for (int i = 2; i < vals.length; i++)
273                 pw.write("|" + escape(vals[i]));
274         }
275         System.out.println(vals[0]);
276         return typeStr;
277     }
278 
279     /** the characters to escape. */
280     private static final String escape = "(){}.?|<>*-+'\\%^";
281 
282     /**
283      * @param s String; the String to escape
284      * @return the String with \ before escaped chars
285      */
286     private static String escape(String s)
287     {
288         String out = "";
289         for (char c : s.toCharArray())
290         {
291             if (escape.indexOf(c) >= 0)
292                 out += "\\";
293             if (c == '"')
294                 out += "&quot;";
295             else
296                 out += c;
297         }
298         return out.trim();
299     }
300 
301     /**
302      * Determine calculated absolute output path (root of the executable or Jar file). In case of an Eclipse run, ../../ is
303      * added to the path to place the results in the root of the project, rather than in target/classes.<br>
304      * See https://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html and
305      * http://stackoverflow.com/questions/320542/how-to-get-the-path-of-a-running-jar-file and
306      * http://stackoverflow.com/questions/3153337/get-current-working-directory-in-java
307      * @throws FileNotFoundException in case file could not be found
308      */
309     private static void makeAbsolutePath() throws FileNotFoundException
310     {
311         URL mainURL = URLResource.getResource("/");
312         String path;
313         try
314         {
315             path = mainURL.toURI().getPath();
316         }
317         catch (URISyntaxException exception)
318         {
319             path = mainURL.getPath();
320         }
321         if (path.endsWith("/target/classes/"))
322         {
323             path = path.substring(0, path.length() - "/target/classes/".length());
324         }
325         path += generatedCodeRelativePath;
326         if (!new File(path).exists())
327         {
328             new File(path).mkdirs();
329         }
330         absoluteRootPath = path;
331         System.out.println("writing into: " + path);
332     }
333 }