1 /* Copyright 2004 The Apache Software Foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 package org.apache.xmlbeans.impl.inst2xsd; 16 17 import org.apache.xmlbeans.SchemaTypeLoader; 18 import org.apache.xmlbeans.XmlBeans; 19 import org.apache.xmlbeans.XmlException; 20 import org.apache.xmlbeans.XmlObject; 21 import org.apache.xmlbeans.XmlOptions; 22 import org.apache.xmlbeans.XmlError; 23 import org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument; 24 import org.apache.xmlbeans.impl.inst2xsd.util.TypeSystemHolder; 25 import org.apache.xmlbeans.impl.tool.CommandLine; 26 27 import java.io.File; 28 import java.io.IOException; 29 import java.io.Reader; 30 import java.util.ArrayList; 31 import java.util.Collection; 32 import java.util.Iterator; 33 import java.util.Set; 34 import java.util.HashSet; 35 36 /** 37 * @author Cezar Andrei (cezar.andrei at bea.com) Date: Jul 16, 2004 38 * 39 * This class generates a set of XMLSchemas from an instance XML document. 40 * 41 * How it works: 42 * - first: pass through all the instances, building a TypeSystemHolder structure 43 * - second: serialize the TypeSystemHolder structure into SchemaDocuments 44 */ 45 public class Inst2Xsd 46 { 47 public static void main(String[] args) 48 { 49 if (args==null || args.length == 0) 50 { 51 printHelp(); 52 System.exit(0); 53 return; 54 } 55 56 Set flags = new HashSet(); 57 flags.add("h"); 58 flags.add("help"); 59 flags.add("usage"); 60 flags.add("license"); 61 flags.add("version"); 62 flags.add("verbose"); 63 flags.add("validate"); 64 65 Set opts = new HashSet(); 66 opts.add("design"); 67 opts.add("simple-content-types"); 68 opts.add("enumerations"); 69 opts.add("outDir"); 70 opts.add("outPrefix"); 71 72 CommandLine cl = new CommandLine(args, flags, opts); 73 Inst2XsdOptions inst2XsdOptions = new Inst2XsdOptions(); 74 75 if (cl.getOpt("license") != null) 76 { 77 CommandLine.printLicense(); 78 System.exit(0); 79 return; 80 } 81 82 if (cl.getOpt("version") != null) 83 { 84 CommandLine.printVersion(); 85 System.exit(0); 86 return; 87 } 88 89 if (cl.getOpt("h") != null || cl.getOpt("help") != null || cl.getOpt("usage") != null) 90 { 91 printHelp(); 92 System.exit(0); 93 return; 94 } 95 96 String[] badopts = cl.getBadOpts(); 97 if (badopts.length > 0) 98 { 99 for (int i = 0; i < badopts.length; i++) 100 System.out.println("Unrecognized option: " + badopts[i]); 101 printHelp(); 102 System.exit(0); 103 return; 104 } 105 106 String design = cl.getOpt("design"); 107 if (design==null) 108 { 109 // default 110 } 111 else if (design.equals("vb")) 112 { 113 inst2XsdOptions.setDesign(Inst2XsdOptions.DESIGN_VENETIAN_BLIND); 114 } 115 else if (design.equals("rd")) 116 { 117 inst2XsdOptions.setDesign(Inst2XsdOptions.DESIGN_RUSSIAN_DOLL); 118 } 119 else if (design.equals("ss")) 120 { 121 inst2XsdOptions.setDesign(Inst2XsdOptions.DESIGN_SALAMI_SLICE); 122 } 123 else 124 { 125 printHelp(); 126 System.exit(0); 127 return; 128 } 129 130 String simpleContent = cl.getOpt("simple-content-types"); 131 if (simpleContent==null) 132 { 133 //default 134 } 135 else if (simpleContent.equals("smart")) 136 { 137 inst2XsdOptions.setSimpleContentTypes(Inst2XsdOptions.SIMPLE_CONTENT_TYPES_SMART); 138 } 139 else if (simpleContent.equals("string")) 140 { 141 inst2XsdOptions.setSimpleContentTypes(Inst2XsdOptions.SIMPLE_CONTENT_TYPES_STRING); 142 } 143 else 144 { 145 printHelp(); 146 System.exit(0); 147 return; 148 } 149 150 String enumerations = cl.getOpt("enumerations"); 151 if (enumerations==null) 152 { 153 // default 154 } 155 else if (enumerations.equals("never")) 156 { 157 inst2XsdOptions.setUseEnumerations(Inst2XsdOptions.ENUMERATION_NEVER); 158 } 159 else 160 { 161 try 162 { 163 int intVal = Integer.parseInt(enumerations); 164 inst2XsdOptions.setUseEnumerations(intVal); 165 } 166 catch (NumberFormatException e) 167 { 168 printHelp(); 169 System.exit(0); 170 return; 171 } 172 } 173 174 File outDir = new File( cl.getOpt("outDir")==null ? "." : cl.getOpt("outDir")); 175 176 String outPrefix = cl.getOpt("outPrefix"); 177 if (outPrefix==null) 178 outPrefix = "schema"; 179 180 inst2XsdOptions.setVerbose((cl.getOpt("verbose") != null)); 181 boolean validate = cl.getOpt("validate")!=null; 182 183 File[] xmlFiles = cl.filesEndingWith(".xml"); 184 XmlObject[] xmlInstances = new XmlObject[xmlFiles.length]; 185 186 if ( xmlInstances.length==0 ) 187 { 188 printHelp(); 189 System.exit(0); 190 return; 191 } 192 193 int i = 0; 194 try 195 { 196 for (i = 0; i < xmlFiles.length; i++) 197 { 198 xmlInstances[i] = XmlObject.Factory.parse(xmlFiles[i]); 199 } 200 } 201 catch (XmlException e) 202 { 203 System.err.println("Invalid xml file: '" + xmlFiles[i].getName() + "'. " + e.getMessage()); 204 return; 205 } 206 catch (IOException e) 207 { 208 System.err.println("Could not read file: '" + xmlFiles[i].getName() + "'. " + e.getMessage()); 209 return; 210 } 211 212 SchemaDocument[] schemaDocs = inst2xsd(xmlInstances, inst2XsdOptions); 213 214 try 215 { 216 for (i = 0; i < schemaDocs.length; i++) 217 { 218 SchemaDocument schema = schemaDocs[i]; 219 220 if (inst2XsdOptions.isVerbose()) 221 System.out.println("----------------------\n\n" + schema); 222 223 schema.save(new File(outDir, outPrefix + i + ".xsd"), new XmlOptions().setSavePrettyPrint()); 224 } 225 } 226 catch (IOException e) 227 { 228 System.err.println("Could not write file: '" + outDir + File.pathSeparator + outPrefix + i + ".xsd" + "'. " + e.getMessage()); 229 return; 230 } 231 232 if (validate) 233 { 234 validateInstances(schemaDocs, xmlInstances); 235 } 236 } 237 238 private static void printHelp() 239 { 240 System.out.println("Generates XMLSchema from instance xml documents."); 241 System.out.println("Usage: inst2xsd [opts] [instance.xml]*"); 242 System.out.println("Options include:"); 243 System.out.println(" -design [rd|ss|vb] - XMLSchema design type"); 244 System.out.println(" rd - Russian Doll Design - local elements and local types"); 245 System.out.println(" ss - Salami Slice Design - global elements and local types"); 246 System.out.println(" vb - Venetian Blind Design (default) - local elements and global complex types"); 247 System.out.println(" -simple-content-types [smart|string] - Simple content types detection (leaf text). Smart is the default"); 248 System.out.println(" -enumerations [never|NUMBER] - Use enumerations. Default value is " + Inst2XsdOptions.ENUMERATION_NOT_MORE_THAN_DEFAULT + "."); 249 System.out.println(" -outDir [dir] - Directory for output files. Default is '.'"); 250 System.out.println(" -outPrefix [file_name_prefix] - Prefix for output file names. Default is 'schema'"); 251 System.out.println(" -validate - Validates input instances agaist generated schemas."); 252 System.out.println(" -verbose - print more informational messages"); 253 System.out.println(" -license - print license information"); 254 System.out.println(" -help - help imformation"); 255 } 256 257 private Inst2Xsd() {} 258 259 // public entry points 260 261 public static SchemaDocument[] inst2xsd(Reader[] instReaders, Inst2XsdOptions options) 262 throws IOException, XmlException 263 { 264 XmlObject[] instances = new XmlObject[ instReaders.length ]; 265 for (int i = 0; i < instReaders.length; i++) 266 { 267 instances[i] = XmlObject.Factory.parse(instReaders[i]); 268 } 269 return inst2xsd(instances, options); 270 } 271 272 public static SchemaDocument[] inst2xsd(XmlObject[] instances, Inst2XsdOptions options) 273 { 274 if (options==null) 275 options = new Inst2XsdOptions(); 276 277 // create structure 278 TypeSystemHolder typeSystemHolder = new TypeSystemHolder(); 279 280 XsdGenStrategy strategy; 281 switch (options.getDesign()) 282 { 283 case Inst2XsdOptions.DESIGN_RUSSIAN_DOLL: 284 strategy = new RussianDollStrategy(); 285 break; 286 287 case Inst2XsdOptions.DESIGN_SALAMI_SLICE: 288 strategy = new SalamiSliceStrategy(); 289 break; 290 291 case Inst2XsdOptions.DESIGN_VENETIAN_BLIND: 292 strategy = new VenetianBlindStrategy(); 293 break; 294 295 default: 296 throw new IllegalArgumentException("Unknown design."); 297 } 298 // processDoc the instance 299 strategy.processDoc(instances, options, typeSystemHolder); 300 301 if (options.isVerbose()) 302 System.out.println("typeSystemHolder.toString(): " + typeSystemHolder); 303 304 SchemaDocument[] sDocs = typeSystemHolder.getSchemaDocuments(); 305 306 return sDocs; 307 } 308 309 private static boolean validateInstances(SchemaDocument[] sDocs, XmlObject[] instances) 310 { 311 SchemaTypeLoader sLoader; 312 Collection compErrors = new ArrayList(); 313 XmlOptions schemaOptions = new XmlOptions(); 314 schemaOptions.setErrorListener(compErrors); 315 try 316 { 317 sLoader = XmlBeans.loadXsd(sDocs, schemaOptions); 318 } 319 catch (Exception e) 320 { 321 if (compErrors.isEmpty() || !(e instanceof XmlException)) 322 { 323 e.printStackTrace(System.out); 324 } 325 System.out.println("\n-------------------\n\nInvalid schemas."); 326 for (Iterator errors = compErrors.iterator(); errors.hasNext(); ) 327 { 328 XmlError xe = (XmlError)errors.next(); 329 System.out.println(xe.getLine() + ":" + xe.getColumn() + " " + xe.getMessage()); 330 } 331 return false; 332 } 333 334 System.out.println("\n-------------------"); 335 boolean result = true; 336 337 for (int i = 0; i < instances.length; i++) 338 { 339 XmlObject xobj; 340 341 try 342 { 343 xobj = sLoader.parse( instances[i].newXMLStreamReader(), null, new XmlOptions().setLoadLineNumbers() ); 344 } 345 catch (XmlException e) 346 { 347 System.out.println("Error:\n" + instances[i].documentProperties().getSourceName() + " not loadable: " + e); 348 e.printStackTrace(System.out); 349 result = false; 350 continue; 351 } 352 353 Collection errors = new ArrayList(); 354 355 if (xobj.schemaType() == XmlObject.type) 356 { 357 System.out.println(instances[i].documentProperties().getSourceName() + " NOT valid. "); 358 System.out.println(" Document type not found." ); 359 result = false; 360 } 361 else if (xobj.validate(new XmlOptions().setErrorListener(errors))) 362 System.out.println("Instance[" + i + "] valid - " + instances[i].documentProperties().getSourceName()); 363 else 364 { 365 System.out.println("Instance[" + i + "] NOT valid - " + instances[i].documentProperties().getSourceName()); 366 for (Iterator it = errors.iterator(); it.hasNext(); ) 367 { 368 XmlError xe = (XmlError)it.next(); 369 System.out.println(xe.getLine() + ":" + xe.getColumn() + " " + xe.getMessage()); 370 } 371 result = false; 372 } 373 } 374 375 return result; 376 } 377 }