├── demo-scalaxb ├── .gitignore └── pom.xml ├── file-list-maven-plugin ├── src │ ├── test │ │ ├── resources │ │ │ ├── a │ │ │ ├── b │ │ │ └── c │ │ │ │ ├── d │ │ │ │ └── e │ │ │ │ ├── g │ │ │ │ └── h │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── davidmoten │ │ │ └── xsdforms │ │ │ └── maven │ │ │ └── FileListerTest.java │ └── main │ │ └── java │ │ └── com │ │ └── github │ │ └── davidmoten │ │ └── xsdforms │ │ └── maven │ │ ├── FileLister.java │ │ └── FileListMojo.java ├── .gitignore └── pom.xml ├── xsd-forms-generator ├── src │ ├── docs │ │ ├── showcase │ │ │ ├── js │ │ │ │ ├── xsd-forms-override.js │ │ │ │ └── xml2json.js │ │ │ └── css │ │ │ │ ├── xsd-forms-style-override.css │ │ │ │ ├── smoothness │ │ │ │ └── images │ │ │ │ │ ├── ui-icons_222222_256x240.png │ │ │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ │ │ ├── ui-icons_454545_256x240.png │ │ │ │ │ ├── ui-icons_888888_256x240.png │ │ │ │ │ ├── ui-icons_cd0a0a_256x240.png │ │ │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ │ │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ │ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ │ │ │ └── ui-bg_highlight-soft_75_cccccc_1x100.png │ │ │ │ ├── timepicker.css │ │ │ │ └── xsd-forms-style.css │ │ ├── screen1.png │ │ └── diagram01.png │ ├── test │ │ ├── resources │ │ │ ├── tick.gif │ │ │ ├── test-pattern-1.xsd │ │ │ ├── annotations-demo.xsd │ │ │ ├── simple.xsd │ │ │ ├── demo-form-expected.xml │ │ │ ├── polrep.xsd │ │ │ └── australian-census-2011.xsd │ │ └── scala │ │ │ └── com │ │ │ └── github │ │ │ └── davidmoten │ │ │ ├── util │ │ │ └── jsTest.scala │ │ │ └── xsdforms │ │ │ ├── tree │ │ │ └── treeUtilTest.scala │ │ │ ├── tstUtil.scala │ │ │ └── generatorTest.scala │ └── main │ │ ├── scala │ │ └── com │ │ │ └── github │ │ │ └── davidmoten │ │ │ ├── xsdforms │ │ │ ├── configuration.scala │ │ │ ├── tree │ │ │ │ ├── util.scala │ │ │ │ ├── node.scala │ │ │ │ ├── xsd-util.scala │ │ │ │ ├── form-creator-util.scala │ │ │ │ ├── ids.scala │ │ │ │ ├── visitor.scala │ │ │ │ ├── html │ │ │ │ │ └── html.scala │ │ │ │ ├── element-wrapper.scala │ │ │ │ └── traversor.scala │ │ │ ├── presentation │ │ │ │ ├── css.scala │ │ │ │ └── annotation.scala │ │ │ └── generator.scala │ │ │ └── util │ │ │ └── js.scala │ │ └── resources │ │ └── template.html ├── update-samples.sh └── pom.xml ├── xsd-forms-html-js ├── src │ └── main │ │ └── resources │ │ ├── js │ │ └── xsd-forms-override.js │ │ └── css │ │ ├── xsd-forms-style-override.css │ │ ├── smoothness │ │ └── images │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ ├── ui-icons_454545_256x240.png │ │ │ ├── ui-icons_888888_256x240.png │ │ │ ├── ui-icons_cd0a0a_256x240.png │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ │ └── ui-bg_highlight-soft_75_cccccc_1x100.png │ │ ├── timepicker.css │ │ └── xsd-forms-style.css ├── .gitignore └── pom.xml ├── .gitignore ├── xsd-forms-maven-plugin-demo ├── src │ ├── main │ │ └── js │ │ │ └── extraScript.js │ └── test │ │ └── java │ │ └── com │ │ └── github │ │ └── davidmoten │ │ └── xsdforms │ │ └── maven │ │ └── GeneratorMojoTest.java └── pom.xml ├── Procfile ├── xsd-forms-generator-webapp ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── davidmoten │ │ │ └── xsdforms │ │ │ ├── store │ │ │ └── Datastore.java │ │ │ └── servlet │ │ │ └── GeneratorServlet.java │ │ └── webapp │ │ └── WEB-INF │ │ └── web.xml └── pom.xml ├── xsd-scalaxb ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── davidmoten │ │ │ └── xsdforms │ │ │ └── Ignore.java │ │ └── xsd │ │ ├── xsd-forms.xsd │ │ ├── miuml-class.xsd │ │ ├── datatypes.dtd │ │ └── xml.xsd └── pom.xml ├── .github ├── dependabot.yml └── workflows │ └── ci.yml └── xsd-forms-maven-plugin ├── pom.xml └── src └── main └── java └── com └── github └── davidmoten └── xsdforms └── maven └── GenerateMojo.java /demo-scalaxb/.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | -------------------------------------------------------------------------------- /file-list-maven-plugin/src/test/resources/a: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /file-list-maven-plugin/src/test/resources/b: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /file-list-maven-plugin/src/test/resources/c/d: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /file-list-maven-plugin/src/test/resources/c/e/g: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /file-list-maven-plugin/src/test/resources/c/e/h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/js/xsd-forms-override.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/js/xsd-forms-override.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/xsd-forms-style-override.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/xsd-forms-style-override.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .settings 3 | .project 4 | .classpath 5 | .cache 6 | -------------------------------------------------------------------------------- /xsd-forms-html-js/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .classpath 3 | .project 4 | .settings 5 | -------------------------------------------------------------------------------- /file-list-maven-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .classpath 3 | .project 4 | .settings 5 | -------------------------------------------------------------------------------- /xsd-forms-maven-plugin-demo/src/main/js/extraScript.js: -------------------------------------------------------------------------------- 1 | 2 | //extra script goes here 3 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/screen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/screen1.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/diagram01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/diagram01.png -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: java -jar xsd-forms-generator-webapp/target/dependency/jetty-runner.jar --port $PORT xsd-forms-generator-webapp/target/*.war 2 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/resources/tick.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/test/resources/tick.gif -------------------------------------------------------------------------------- /xsd-forms-generator/update-samples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | rm -rf src/docs/showcase 4 | mkdir src/docs/showcase 5 | cp -r target/generated-webapp/* src/docs/showcase 6 | 7 | -------------------------------------------------------------------------------- /xsd-forms-generator-webapp/src/main/java/com/github/davidmoten/xsdforms/store/Datastore.java: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.store; 2 | 3 | public class Datastore { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-generator/src/docs/showcase/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmoten/xsd-forms/HEAD/xsd-forms-html-js/src/main/resources/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /xsd-scalaxb/src/main/java/com/github/davidmoten/xsdforms/Ignore.java: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms; 2 | 3 | /** 4 | * Exists solely to force generation of javadoc so maven release plugin doesnt' fail. 5 | **/ 6 | public class Ignore { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/timepicker.css: -------------------------------------------------------------------------------- 1 | /* css for timepicker */ 2 | .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } 3 | .ui-timepicker-div dl { text-align: left; } 4 | .ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; } 5 | .ui-timepicker-div dl dd { margin: 0 10px 10px 65px; } 6 | .ui-timepicker-div td { font-size: 90%; } 7 | .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/timepicker.css: -------------------------------------------------------------------------------- 1 | /* css for timepicker */ 2 | .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } 3 | .ui-timepicker-div dl { text-align: left; } 4 | .ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; } 5 | .ui-timepicker-div dl dd { margin: 0 10px 10px 65px; } 6 | .ui-timepicker-div td { font-size: 90%; } 7 | .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/configuration.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms 2 | 3 | case class Configuration(header: Option[String], footer: Option[String], 4 | extraImports: Option[String], extraScript: Option[String], extraCss: Option[String]) 5 | 6 | case class Options(targetNamespace: String, idPrefix: Prefix) 7 | 8 | case class Prefix(value: String) { 9 | override def toString = value 10 | } -------------------------------------------------------------------------------- /xsd-forms-maven-plugin-demo/src/test/java/com/github/davidmoten/xsdforms/maven/GeneratorMojoTest.java: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.maven; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import java.io.File; 6 | 7 | import org.junit.Test; 8 | 9 | public class GeneratorMojoTest { 10 | 11 | @Test 12 | public void testFilesWereGenerated() { 13 | assertTrue(new File("target/generated-resources/form.html").exists()); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "maven" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/scala/com/github/davidmoten/util/jsTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.util 2 | 3 | import org.junit.Test 4 | import org.junit.Assert.assertEquals 5 | 6 | @Test 7 | class JSTest { 8 | 9 | import org.junit.Assert._ 10 | 11 | @Test 12 | def testJS { 13 | val js = JS() 14 | .line("function %s(doc,%s) {", "logit", "name") 15 | .line(" console.log(doc);") 16 | .line("}") 17 | println(js) 18 | val expected = """ 19 | function logit(doc,name) { 20 | console.log(doc); 21 | }""" 22 | assertEquals(expected, js.toString) 23 | } 24 | } -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/util/js.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.util 2 | 3 | /** 4 | * Utility class for building javascript statements. 5 | */ 6 | private[davidmoten] case class JS() { 7 | val b = new StringBuffer() 8 | 9 | def line: JS = line("") 10 | 11 | def line(s: String, params: Object*): JS = { 12 | b append "\n" 13 | b append String.format(s, params: _*) 14 | this 15 | } 16 | 17 | def append(s: String, params: Object*): JS = { 18 | b append String.format(s, params: _*) 19 | this 20 | } 21 | 22 | override def toString = b.toString 23 | } -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/resources/test-pattern-1.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /file-list-maven-plugin/src/test/java/com/github/davidmoten/xsdforms/maven/FileListerTest.java: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.maven; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.File; 6 | 7 | import org.junit.Test; 8 | 9 | public class FileListerTest { 10 | 11 | @Test 12 | public void testWithPrefix() { 13 | String s = FileLister.listFiles("boo", new File("src/test/resources")); 14 | System.out.println(s); 15 | assertEquals("boo/a\nboo/b\nboo/c/d\nboo/c/e/g\nboo/c/e/h",s); 16 | } 17 | 18 | @Test 19 | public void testWithoutPrefix() { 20 | String s = FileLister.listFiles("", new File("src/test/resources")); 21 | System.out.println(s); 22 | assertEquals("a\nb\nc/d\nc/e/g\nc/e/h",s); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /xsd-forms-generator-webapp/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Generator 7 | com.github.davidmoten.xsdforms.servlet.GeneratorServlet 8 | 9 | 10 | 11 | Generator 12 | /generate 13 | 14 | 15 | 16 | index.jsp 17 | index.html 18 | 19 | 20 | 21 | 30 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/scala/com/github/davidmoten/xsdforms/tree/treeUtilTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree 2 | 3 | import org.junit.Test 4 | import TreeUtil.parseMakeVisibleMap 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Assert.assertTrue 7 | import org.junit.Assert.fail 8 | 9 | @Test 10 | class TreeUtilTest { 11 | import org.junit.Assert._ 12 | 13 | import TreeUtil._ 14 | 15 | @Test 16 | def testParseSingle { 17 | assertEquals( 18 | Map("true" -> 1), 19 | parseMakeVisibleMap(Some("true->1"))) 20 | } 21 | 22 | @Test 23 | def testParseThree { 24 | assertEquals( 25 | Map("true" -> 1, "yes" -> 2, "boo" -> 3), 26 | parseMakeVisibleMap(Some("true->1,yes->2,boo->3"))) 27 | } 28 | 29 | @Test 30 | def testParseNone { 31 | assertTrue(parseMakeVisibleMap(None).isEmpty) 32 | } 33 | 34 | @Test 35 | def testParseBlankReturnsEmptyMap { 36 | try { 37 | assertTrue(parseMakeVisibleMap(Some("")).isEmpty) 38 | fail 39 | } catch { 40 | case _: Throwable => 41 | } 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /file-list-maven-plugin/src/main/java/com/github/davidmoten/xsdforms/maven/FileLister.java: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.maven; 2 | 3 | import java.io.File; 4 | import java.util.Arrays; 5 | 6 | public class FileLister { 7 | 8 | public static String listFiles(String prefix, File f) { 9 | String[] items = add(prefix, null, f).split("\n"); 10 | Arrays.sort(items); 11 | StringBuilder s = new StringBuilder(); 12 | for (String item : items) { 13 | if (s.length() > 0) 14 | s.append("\n"); 15 | s.append(item); 16 | } 17 | return s.toString(); 18 | 19 | } 20 | 21 | private static String add(String prefix, String path, File f) { 22 | StringBuilder s = new StringBuilder(); 23 | 24 | String base; 25 | if (path == null) 26 | base = prefix; 27 | else if (path.length() == 0) 28 | base = f.getName(); 29 | else 30 | base = path + "/" + f.getName(); 31 | if (f.isDirectory()) 32 | for (File file : f.listFiles()) { 33 | if (!file.getName().startsWith(".")) { 34 | if (s.length() > 0) 35 | s.append('\n'); 36 | s.append(add(prefix, base, file)); 37 | } 38 | } 39 | else if (!f.getName().startsWith(".")) 40 | s.append(base); 41 | return s.toString(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/tree/util.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree 2 | 3 | import xsd._ 4 | 5 | import javax.xml.namespace.QName 6 | 7 | import scalaxb._ 8 | 9 | /** 10 | * *************************************************************** 11 | * 12 | * Util 13 | * 14 | * 15 | * ************************************************************** 16 | */ 17 | 18 | /** 19 | * Utility methods. 20 | * 21 | */ 22 | private[xsdforms] object Util { 23 | def unexpected(s: String) = throw new RuntimeException(s) 24 | def unexpected = throw new RuntimeException 25 | } 26 | 27 | private[tree] case class XsdDatatype(name: String, pattern: Option[String] = None) 28 | case class XsdElement(name: String) 29 | 30 | 31 | /** 32 | * ************************************************************** 33 | * 34 | * Instances 35 | * 36 | * 37 | * ************************************************************** 38 | */ 39 | 40 | private[xsdforms] case class Instances(heirarchy: Seq[Int] = List(), indentsDelta: Int = 0) { 41 | def add(instance: Int): Instances = Instances(heirarchy :+ instance, indentsDelta) 42 | def add(instance: Int, suppressIndent: Boolean) = 43 | Instances(heirarchy :+ instance, indentsDelta - (if (suppressIndent) 1 else 0)) 44 | override def toString = heirarchy.mkString("_") 45 | def last = heirarchy.last 46 | def indentCount = heirarchy.size + indentsDelta 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/scala/com/github/davidmoten/xsdforms/tstUtil.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms { 2 | 3 | import org.junit.Test 4 | import org.junit.Before 5 | import xsd.Schema 6 | import org.junit.runners.BlockJUnit4ClassRunner 7 | import org.junit.runner.notification.Failure 8 | import java.io.File 9 | import java.io.InputStream 10 | import tree._ 11 | 12 | object TstUtil { 13 | 14 | import org.apache.commons.io._ 15 | 16 | implicit val idPrefix = Prefix("c-") 17 | 18 | def generate( 19 | idPrefix: String, 20 | schemaInputStream: InputStream, 21 | rootElement: String, 22 | outputFile: File, 23 | extraScript: Option[String] = None) { 24 | 25 | //write results to a file 26 | outputFile.getParentFile().mkdirs 27 | val fos = new java.io.FileOutputStream(outputFile); 28 | Generator.generateHtml(schemaInputStream, fos, idPrefix, Some(rootElement)) 29 | fos.close 30 | } 31 | 32 | def generateDemoForm(file: File) { 33 | println("generating demo form") 34 | generate( 35 | idPrefix = idPrefix.toString, 36 | schemaInputStream = TstUtil.getClass().getResourceAsStream("/demo.xsd"), 37 | rootElement = "main", 38 | outputFile = file) 39 | } 40 | 41 | def generateDemoForm { 42 | val file = new File("target/generated-webapp/demo-form.html") 43 | generateDemoForm(file) 44 | } 45 | 46 | def copyHtmlJs() { 47 | val directory = new File("target/generated-webapp") 48 | FileUtils.deleteDirectory(new File(directory, "css")) 49 | FileUtils.deleteDirectory(new File(directory, "js")) 50 | FileUtils.copyDirectory(new File("../xsd-forms-html-js/src/main/resources"), directory) 51 | } 52 | 53 | } 54 | } -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/presentation/css.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.presentation 2 | 3 | private[xsdforms] object Css { 4 | val ClassInvisible = "invisible" 5 | val ClassSequence = "sequence" 6 | val ClassSequenceLabel = "sequence-label" 7 | val ClassSequenceContent = "sequence-content" 8 | val ClassFieldset = "fieldset" 9 | val ClassChoiceLabel = "choice-label" 10 | val ClassDivChoiceItem = "div-choice-item" 11 | val ClassItemNumber = "item-number" 12 | val ClassItemTitle = "item-title" 13 | val ClassItemLabel = "item-label" 14 | val ClassItemInput = "item-input" 15 | val ClassItemHelp = "item-help" 16 | val ClassItemBefore = "item-before" 17 | val ClassItemAfter = "item-after" 18 | val ClassItemPath = "item-path" 19 | val ClassItemEnclosing = "item-enclosing" 20 | val ClassItemError = "item-error" 21 | val ClassChoiceItem = "choice-item" 22 | val ClassNonRepeatingTitle = "non-repeating-title" 23 | val ClassRepeatButton = "repeat-button" 24 | val ClassRemoveButton = "remove-button" 25 | val ClassRemoveButtonContainer = "remove-button-container" 26 | val ClassRepeatingEnclosing = "repeating-enclosing" 27 | val ClassItemInputTextarea = "item-input-textarea" 28 | val ClassItemInputText = "item-input-text" 29 | val ClassSelect = "select" 30 | val ClassChoice = "choice" 31 | val ClassWhite = "white" 32 | val ClassSmall = "small" 33 | val ClassClear = "clr" 34 | val ClassItemDescription = "item-description" 35 | val ClassTimePicker = "timepickerclass" 36 | val ClassDatePicker = "datepickerclass" 37 | val ClassDateTimePicker = "datetimepickerclass" 38 | val ClassMinOccursZero = "min-occurs-zero" 39 | val ClassMinOccursZeroContainer = "min-occurs-zero-container" 40 | val ClassMinOccursZeroLabel = "min-occurs-zero-label" 41 | } 42 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/tree/node.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree 2 | 3 | import scala.collection.mutable.MutableList 4 | import javax.xml.namespace.QName 5 | import xsd._ 6 | 7 | //every element is either a sequence, choice or simpleType 8 | // simpleTypes may be based on string, decimal, boolean, date, datetime 9 | // and may be restricted to a regex pattern, have min, max ranges 10 | // or be an enumeration. all elements may have minOccurs and maxOccurs 11 | //attributes. 12 | 13 | private[tree] case class Sequence(group: ExplicitGroupable) 14 | private[tree] case class Choice(group: ExplicitGroupable) 15 | private[tree] case class BaseType(qName: QName) 16 | 17 | private[tree] sealed trait Node { 18 | val element: ElementWrapper 19 | def isAnonymous = element.name.isEmpty 20 | } 21 | 22 | private[tree] sealed trait NodeGroup extends Node { 23 | val children: MutableList[Node] = MutableList() 24 | } 25 | 26 | // immutable would be preferrable but should be safe because not changed after tree created 27 | private[tree] sealed trait NodeBasic extends Node 28 | 29 | private[tree] sealed trait BasicType 30 | private[tree] case class BasicTypeSimple(typ: SimpleType) extends BasicType 31 | private[tree] case class BasicTypeBase(typ: BaseType) extends BasicType 32 | 33 | //TODO stop using mutable types 34 | private[tree] case class NodeSequence(element: ElementWrapper, 35 | override val children: MutableList[Node]) extends NodeGroup 36 | private[tree] case class NodeChoice(element: ElementWrapper, choice: Choice, 37 | override val children: MutableList[Node]) extends NodeGroup 38 | private[tree] case class NodeSimpleType(element: ElementWrapper, typ: SimpleType) extends NodeBasic 39 | private[tree] case class NodeBaseType(element: ElementWrapper, typ: BaseType) extends NodeBasic 40 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/resources/annotations-demo.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 'header' here 10 | ]]> 11 | 12 | 13 | 'footer' here.

15 | ]]> 16 |
17 | 18 | 21 | 22 |
23 |
24 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | ## Does continuous integration build with Java 8 and 11 and 4 | ## if succeeds and due to a dependabot pull request (minor or 5 | ## patch verson change) it will automatically merge the PR. 6 | 7 | ## Unlike many sample automerge workflows this does not rely 8 | ## on third-party libraries apart from the official dependabot 9 | ## repository ones. This reduces the security risk significantly 10 | ## (we don't want to unknowingly merge malicious code or expose 11 | ## secrets to a malicious third party). 12 | 13 | on: [push, pull_request] 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | matrix: 20 | java: ['8'] 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Set up JDK ${{ matrix.java }} 24 | uses: actions/setup-java@v4 25 | with: 26 | java-version: ${{ matrix.java }} 27 | distribution: 'temurin' 28 | - name: Build with Maven 29 | run: mvn --batch-mode --update-snapshots verify 30 | - uses: codecov/codecov-action@v4 31 | with: 32 | file: ./**/target/site/jacoco/jacoco.xml 33 | name: codecov 34 | dependabot: 35 | runs-on: ubuntu-latest 36 | needs: build 37 | permissions: 38 | pull-requests: write 39 | contents: write 40 | if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request' }} 41 | steps: 42 | - name: Dependabot metadata 43 | id: metadata 44 | uses: dependabot/fetch-metadata@v2.1.0 45 | with: 46 | github-token: "${{ secrets.GITHUB_TOKEN }}" 47 | - name: Enable auto-merge for Dependabot PRs 48 | if: ${{!contains(steps.metadata.outputs.dependency-names, 'maven-plugin-api') && (steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch')}} 49 | run: gh pr merge --auto --rebase "$PR_URL" 50 | env: 51 | PR_URL: ${{github.event.pull_request.html_url}} 52 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 53 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/tree/xsd-util.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree 2 | 3 | /** 4 | * Utility methods and constants for XML Schemas (XSD). 5 | */ 6 | private[xsdforms] object XsdUtil { 7 | 8 | import scalaxb.DataRecord 9 | import javax.xml.namespace.QName 10 | 11 | val Xsd = "http://www.w3.org/2001/XMLSchema" 12 | val AppInfoSchema = "http://moten.david.org/xsd-forms" 13 | 14 | def toQName[T](d: DataRecord[T]) = 15 | new QName(d.namespace.getOrElse(null), d.key.getOrElse(null)) 16 | def qn(namespaceUri: String, localPart: String) = new QName(namespaceUri, localPart) 17 | def qn(localPart: String): QName = new QName(Xsd, localPart) 18 | def qn(datatype: XsdDatatype): QName = qn(Xsd, datatype.name) 19 | 20 | val QnXsdExtension = qn("extension") 21 | val QnXsdSequence = qn("sequence") 22 | val QnXsdChoice = qn("choice") 23 | val QnXsdAppInfo = qn("appinfo") 24 | val QnXsdElement = qn("element") 25 | 26 | //TODO use enumeration 27 | val XsdDateTime = XsdDatatype("dateTime") 28 | val XsdDate = XsdDatatype("date") 29 | val XsdTime = XsdDatatype("time") 30 | val XsdInteger = XsdDatatype("integer", Some("\\d+")) 31 | val XsdInt = XsdDatatype("int", Some("-?\\d+")) 32 | val XsdLong = XsdDatatype("long", Some("-?\\d+")) 33 | val XsdShort = XsdDatatype("short", Some("-?\\d+")) 34 | val XsdPositiveInteger = XsdDatatype("positiveInteger", Some("[1-9]\\d*")) 35 | val XsdNegativeInteger = XsdDatatype("negativeInteger", Some("-[1-9]\\d*")) 36 | 37 | //TODO allow zero for non-positive integer (adjust regex) 38 | val XsdNonPositiveInteger = XsdDatatype("nonPositiveInteger", Some("(-\\d+)|0")) 39 | val XsdNonNegativeInteger = XsdDatatype("nonNegativeInteger", Some("\\d+")) 40 | val XsdDecimal = XsdDatatype("decimal", Some("-?\\d+(\\.\\d*)?")) 41 | val XsdBoolean = XsdDatatype("boolean") 42 | val XsdString = XsdDatatype("string") 43 | val XsdDouble = XsdDatatype("double", Some("-?\\d(\\.\\d*)?([eE]-?\\d+)?")) 44 | val XsdFloat = XsdDatatype("float", Some("-?\\d(\\.\\d*)?([eE]-?\\d+)?")) 45 | val XsdAttribute = XsdDatatype("attribute", None) 46 | val XsdAnnotation = XsdDatatype("annotation", None) 47 | } -------------------------------------------------------------------------------- /file-list-maven-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.github.davidmoten.xsdforms 6 | xsd-forms 7 | 0.2.2-SNAPSHOT 8 | 9 | file-list-maven-plugin 10 | ${project.artifactId} 11 | maven-plugin 12 | 13 | UTF-8 14 | 15 | 16 | 17 | org.apache.maven 18 | maven-plugin-api 19 | 3.6.0 20 | provided 21 | 22 | 23 | org.apache.maven.plugin-tools 24 | maven-plugin-annotations 25 | 3.9.0 26 | provided 27 | 28 | 29 | org.codehaus.plexus 30 | plexus-utils 31 | 3.5.1 32 | 33 | 34 | junit 35 | junit 36 | 4.13.2 37 | test 38 | 39 | 40 | 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-plugin-plugin 45 | 3.9.0 46 | 47 | file-list 48 | true 49 | 50 | 51 | 52 | mojo-descriptor 53 | 54 | descriptor 55 | 56 | 57 | 58 | help-goal 59 | 60 | helpmojo 61 | 62 | 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-compiler-plugin 68 | 69 | 1.8 70 | 1.8 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/tree/form-creator-util.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree 2 | 3 | private[tree] object TreeUtil { 4 | import xsd.Annotatedable 5 | import XsdUtil.AppInfoSchema 6 | 7 | def parseMakeVisibleMap(value: Option[String]): Map[String, Int] = { 8 | import Util._ 9 | 10 | val Problem = "could not parse makeVisible, expecting 'value1->1,value2->2' (pairs delimited by comma and key value delimited by '->'" 11 | value match { 12 | case Some(s) => 13 | s.split(",") 14 | .toList 15 | .map( 16 | x => { 17 | val items = x.split("->") 18 | if (items.length < 2) 19 | unexpected(Problem) 20 | (items(0), items(1).toInt) 21 | }).toMap 22 | case None => Map() 23 | } 24 | } 25 | 26 | } 27 | 28 | private[tree] case class ElementWithNumber(element: ElementWrapper, number: Int) 29 | 30 | //Use Vector because has O(1) append 31 | private[tree] case class HtmlJs(html: Vector[String], js: Vector[String]) { 32 | def addHtml(html2: String) = HtmlJs(html.+:(html2), js) 33 | def addJs(js2: String) = HtmlJs(html, js.+:(js2)) 34 | } 35 | 36 | private class ElementNumbersAssigner(node: Node) { 37 | 38 | private def assign(node: Node, number: Int): Map[ElementWrapper, Int] = { 39 | val m = Map(node.element -> (number + 1)) 40 | node match { 41 | case n: NodeGroup => 42 | n.children.foldLeft(m)( 43 | (map, nd) => map ++ assign(nd, number + map.size)) 44 | case _ => 45 | m 46 | } 47 | } 48 | 49 | val assignments = assign(node, 0) 50 | 51 | } 52 | 53 | private[tree] trait FormCreatorState { 54 | import com.github.davidmoten.xsdforms.tree.html.Html 55 | import com.github.davidmoten.xsdforms.Options 56 | 57 | val options: Options 58 | 59 | val tree: Node 60 | 61 | implicit val idPrefix = options.idPrefix 62 | 63 | val html: Html 64 | 65 | //assign element numbers so that order of display on page 66 | //will match order of element numbers. To do this must 67 | //traverse children left to right before siblings 68 | private val elementNumbers = new ElementNumbersAssigner(tree).assignments 69 | 70 | implicit def toElementWithNumber(element: ElementWrapper): ElementWithNumber = 71 | ElementWithNumber(element, elementNumber(element)) 72 | 73 | private def elementNumber(e: ElementWrapper): Int = 74 | elementNumbers.get(e).get; 75 | } 76 | 77 | 78 | -------------------------------------------------------------------------------- /demo-scalaxb/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.github.davidmoten.xsdforms 5 | xsd-forms 6 | 0.2.2-SNAPSHOT 7 | 8 | demo-scalaxb 9 | ${project.artifactId} 10 | 11 | 12 | 13 | org.apache.maven.plugins 14 | maven-deploy-plugin 15 | 3.1.1 16 | 17 | true 18 | 19 | 20 | 21 | 22 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /file-list-maven-plugin/src/main/java/com/github/davidmoten/xsdforms/maven/FileListMojo.java: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.maven; 2 | 3 | /* 4 | * Copyright 2001-2005 The Apache Software Foundation. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import java.io.File; 20 | import java.io.FileOutputStream; 21 | import java.io.IOException; 22 | import java.nio.charset.Charset; 23 | 24 | import org.apache.maven.plugin.AbstractMojo; 25 | import org.apache.maven.plugin.MojoExecutionException; 26 | import org.apache.maven.plugins.annotations.LifecyclePhase; 27 | import org.apache.maven.plugins.annotations.Mojo; 28 | import org.apache.maven.plugins.annotations.Parameter; 29 | 30 | /** 31 | * Goal which generates file list. 32 | * 33 | */ 34 | @Mojo(name = "list", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, threadSafe = true) 35 | public class FileListMojo extends AbstractMojo { 36 | /** 37 | * The file to contain the file list. 38 | * 39 | */ 40 | @Parameter(property = "output", defaultValue = "${project.build.directory}/generated-resources/file-list.txt") 41 | private File output; 42 | 43 | /** 44 | * The directory to list. 45 | * 46 | */ 47 | @Parameter(property = "directory", defaultValue = "${basedir}/src/main/resources") 48 | private File directory; 49 | 50 | @Parameter(property = "prefix", defaultValue = "") 51 | private String prefix; 52 | 53 | @Override 54 | public void execute() throws MojoExecutionException { 55 | if (prefix == null) 56 | prefix = ""; 57 | getLog().info( 58 | "writing list of " + directory + " to " + output 59 | + " with prefix " + prefix); 60 | String list = FileLister.listFiles(prefix, directory); 61 | getLog().info("list=\n"+list); 62 | output.getParentFile().mkdirs(); 63 | try { 64 | FileOutputStream fos = new FileOutputStream(output); 65 | fos.write(list.getBytes(Charset.forName("UTF-8"))); 66 | fos.close(); 67 | } catch (IOException e) { 68 | throw new MojoExecutionException(e.getMessage(), e); 69 | } 70 | getLog().info("written to " + output); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /xsd-forms-maven-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.github.davidmoten.xsdforms 6 | xsd-forms 7 | 0.2.2-SNAPSHOT 8 | 9 | xsd-forms-maven-plugin 10 | ${project.artifactId} 11 | maven-plugin 12 | 13 | UTF-8 14 | 15 | 16 | 17 | org.apache.maven 18 | maven-plugin-api 19 | 3.6.0 20 | provided 21 | 22 | 23 | org.apache.maven.plugin-tools 24 | maven-plugin-annotations 25 | 3.9.0 26 | provided 27 | 28 | 29 | org.codehaus.plexus 30 | plexus-utils 31 | 3.5.1 32 | 33 | 34 | junit 35 | junit 36 | 4.13.2 37 | test 38 | 39 | 40 | ${project.parent.groupId} 41 | xsd-forms-generator 42 | ${project.parent.version} 43 | 44 | 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-plugin-plugin 50 | 3.9.0 51 | 52 | xsd-forms 53 | true 54 | 55 | 56 | 57 | mojo-descriptor 58 | 59 | descriptor 60 | 61 | 62 | 63 | help-goal 64 | 65 | helpmojo 66 | 67 | 68 | 69 | 70 | 71 | org.apache.maven.plugins 72 | maven-compiler-plugin 73 | 74 | 1.8 75 | 1.8 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /xsd-forms-generator-webapp/src/main/java/com/github/davidmoten/xsdforms/servlet/GeneratorServlet.java: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.servlet; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | import javax.servlet.ServletException; 8 | import javax.servlet.http.HttpServlet; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | import scala.Option; 13 | 14 | import com.github.davidmoten.xsdforms.Generator; 15 | 16 | public class GeneratorServlet extends HttpServlet { 17 | 18 | private static final long serialVersionUID = -1329200353122439077L; 19 | private static final String PARAMETER_ROOT_ELEMENT = "rootElement"; 20 | private static final String PARAMETER_ID_PREFIX = "idPrefix"; 21 | private static final String ACTION_ZIP = "zip"; 22 | 23 | @Override 24 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) 25 | throws ServletException, IOException { 26 | String schema = req.getParameter("schema"); 27 | InputStream schemaIn = new ByteArrayInputStream(schema.getBytes()); 28 | String idPrefix = nullToBlank(req.getParameter(PARAMETER_ID_PREFIX)); 29 | String rootElementParam = blankToNull(req.getParameter(PARAMETER_ROOT_ELEMENT)); 30 | Option rootElement = Option.apply(rootElementParam); 31 | 32 | String action = req.getParameter("action"); 33 | if (ACTION_ZIP.equals(action)) { 34 | returnZip(resp, schemaIn, idPrefix, rootElement); 35 | } else { 36 | returnHtml(resp, schemaIn, idPrefix, rootElement); 37 | } 38 | } 39 | 40 | private void returnZip(HttpServletResponse resp, InputStream schemaIn, 41 | String idPrefix, Option rootElement) throws IOException { 42 | resp.setContentType("application/zip"); 43 | resp.setHeader("Content-Disposition", 44 | "attachment; filename=site.zip"); 45 | Generator.generateZip(schemaIn, resp.getOutputStream(), idPrefix, 46 | rootElement); 47 | } 48 | 49 | 50 | private void returnHtml(HttpServletResponse resp, InputStream schemaIn, 51 | String idPrefix, Option rootElement) throws IOException { 52 | resp.setContentType("text/html"); 53 | Generator.generateHtml(schemaIn, resp.getOutputStream(), idPrefix, 54 | rootElement); 55 | } 56 | 57 | @Override 58 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) 59 | throws ServletException, IOException { 60 | doPost(req,resp); 61 | } 62 | 63 | private static String blankToNull(String s) { 64 | if (s != null && s.trim().length() == 0) 65 | return null; 66 | else 67 | return s; 68 | } 69 | 70 | private static String nullToBlank(String s) { 71 | if (s == null) 72 | return ""; 73 | else 74 | return s; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/tree/ids.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree 2 | 3 | private[xsdforms] object Ids { 4 | 5 | import com.github.davidmoten.xsdforms.{Prefix} 6 | 7 | val InstanceDelimiter = "-instance-" 8 | val ChoiceIndexDelimiter = "-choice-" 9 | 10 | def getItemId(number: Int, instances: Instances)(implicit idPrefix: Prefix) = 11 | idPrefix + "item-" + number + InstanceDelimiter + instances 12 | 13 | def getItemName(number: Int, instances: Instances)(implicit idPrefix: Prefix): String = 14 | idPrefix + "item-input-" + number + InstanceDelimiter + instances; 15 | 16 | def getItemErrorId(number: Int, instances: Instances)(implicit idPrefix: Prefix): String = 17 | idPrefix + "item-error-" + number + InstanceDelimiter + instances 18 | 19 | def getChoiceItemId(number: Int, index: Int, 20 | instances: Instances)(implicit idPrefix: Prefix): String = 21 | getItemId(number, instances)(idPrefix) + ChoiceIndexDelimiter + index 22 | 23 | def getChoiceItemName(number: Int, instances: Instances)(implicit idPrefix: Prefix): String = 24 | idPrefix + "item-input-" + number + InstanceDelimiter + instances 25 | 26 | def choiceContentId(number: Int, index: Int, 27 | instances: Instances)(implicit idPrefix: Prefix): String = 28 | idPrefix + "choice-content-" + number + InstanceDelimiter + 29 | instances + ChoiceIndexDelimiter + index 30 | 31 | def getItemId(number: Int, enumeration: Integer, 32 | instances: Instances)(implicit idPrefix: Prefix): String = 33 | getItemId(number, instances) + "-" + enumeration 34 | 35 | def getRepeatButtonId(number: Int, instances: Instances)(implicit idPrefix: Prefix): String = 36 | idPrefix + "repeat-button-" + number + InstanceDelimiter + instances 37 | 38 | def getRemoveButtonId(number: Int, instances: Instances)(implicit idPrefix: Prefix): String = 39 | idPrefix + "remove-button-" + number + InstanceDelimiter + instances 40 | 41 | def getRepeatingEnclosingId(number: Int, 42 | instances: Instances)(implicit idPrefix: Prefix): String = 43 | idPrefix + "repeating-enclosing-" + number + InstanceDelimiter + instances 44 | 45 | def getMinOccursZeroId(number: Int, instances: Instances)(implicit idPrefix: Prefix): String = 46 | idPrefix + "min-occurs-zero-" + number + InstanceDelimiter + instances 47 | 48 | def getMinOccursZeroName(number: Int, 49 | instances: Instances)(implicit idPrefix: Prefix): String = 50 | idPrefix + "min-occurs-zero-name" + number + InstanceDelimiter + instances 51 | 52 | def getItemEnclosingId(number: Int, instances: Instances)(implicit idPrefix: Prefix) = 53 | idPrefix + "item-enclosing-" + number + InstanceDelimiter + instances 54 | 55 | def getPathId(number: Int, instances: Instances)(implicit idPrefix: Prefix) = 56 | idPrefix + "item-path-" + number + InstanceDelimiter + instances 57 | } -------------------------------------------------------------------------------- /xsd-forms-maven-plugin-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.github.davidmoten.xsdforms 5 | xsd-forms 6 | 0.2.2-SNAPSHOT 7 | 8 | xsd-forms-maven-plugin-demo 9 | ${project.artifactId} 10 | jar 11 | 12 | 13 | 14 | junit 15 | junit 16 | 4.13.2 17 | test 18 | 19 | 20 | 21 | 22 | 23 | ${project.parent.groupId} 24 | xsd-forms-maven-plugin 25 | ${project.parent.version} 26 | 27 | 28 | 29 | ${project.parent.groupId} 30 | demo-scalaxb 31 | ${project.parent.version} 32 | 33 | 34 | 35 | 36 | 37 | generate 38 | 39 | 40 | 41 | 42 | 43 | /demo.xsd 44 | 45 | a- 46 | 47 | main 48 | 49 | ${project.build.directory}/generated-resources 50 | 51 | 52 | 53 | org.codehaus.mojo 54 | build-helper-maven-plugin 55 | 3.3.0 56 | 57 | 58 | add-resource 59 | generate-resources 60 | 61 | add-resource 62 | 63 | 64 | 65 | 66 | ${project.build.directory}/generated-resources 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-deploy-plugin 76 | 3.1.1 77 | 78 | true 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /xsd-forms-maven-plugin/src/main/java/com/github/davidmoten/xsdforms/maven/GenerateMojo.java: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.maven; 2 | 3 | /* 4 | * Copyright 2001-2005 The Apache Software Foundation. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import java.io.File; 20 | import java.io.FileInputStream; 21 | import java.io.FileNotFoundException; 22 | import java.io.InputStream; 23 | 24 | import org.apache.maven.plugin.AbstractMojo; 25 | import org.apache.maven.plugin.MojoExecutionException; 26 | import org.apache.maven.plugins.annotations.LifecyclePhase; 27 | import org.apache.maven.plugins.annotations.Mojo; 28 | import org.apache.maven.plugins.annotations.Parameter; 29 | 30 | import scala.Option; 31 | 32 | import com.github.davidmoten.xsdforms.Generator; 33 | 34 | /** 35 | * Goal which generates form and dependent files. 36 | * 37 | */ 38 | @Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, threadSafe = true) 39 | public class GenerateMojo extends AbstractMojo { 40 | /** 41 | * The directory to write the files to. 42 | * 43 | */ 44 | @Parameter(property = "xsdforms.output.directory", defaultValue = "${project.build.directory}/generated-resources") 45 | private File outputDirectory; 46 | 47 | /** 48 | * The schema path (on classpath or as file) 49 | * 50 | */ 51 | @Parameter(property = "xsdforms.schema", required = true) 52 | private String schema; 53 | 54 | /** 55 | * The id prefix in generated html. 56 | * 57 | */ 58 | @Parameter(property = "xsdforms.id.prefix") 59 | private String idPrefix; 60 | 61 | /** 62 | * Top level element from schema to use as root level element in xml. 63 | * 64 | */ 65 | @Parameter(property = "xsdforms.root.element") 66 | private String rootElement; 67 | 68 | @Override 69 | public void execute() throws MojoExecutionException { 70 | 71 | if (schema == null) 72 | throw new MojoExecutionException("schema must be specified"); 73 | // look first on classpath 74 | InputStream schemaIn = getInputStreamFromClasspathOrFile(schema); 75 | 76 | Generator.generateDirectory(schemaIn, outputDirectory, idPrefix, 77 | Option.apply(rootElement)); 78 | } 79 | 80 | private static InputStream getInputStreamFromClasspathOrFile(String path) 81 | throws MojoExecutionException { 82 | 83 | InputStream in = GenerateMojo.class.getResourceAsStream(path); 84 | // then on file system 85 | if (in == null) 86 | try { 87 | in = new FileInputStream(path); 88 | } catch (FileNotFoundException e) { 89 | throw new MojoExecutionException(e.getMessage() + " path=" 90 | + path, e); 91 | } 92 | return in; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /xsd-scalaxb/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.github.davidmoten.xsdforms 5 | xsd-forms 6 | 0.2.2-SNAPSHOT 7 | 8 | xsd-scalaxb 9 | ${project.artifactId} 10 | 11 | 12 | 13 | net.alchim31.maven 14 | scala-maven-plugin 15 | ${scala.plugin.version} 16 | 17 | 18 | 19 | compile 20 | testCompile 21 | 22 | 23 | 24 | -Xms64m 25 | -Xmx1024m 26 | -XX:MaxPermSize=256m 27 | 28 | 29 | 30 | -dependencyfile 31 | ${project.build.directory}/.scala_dependencies 32 | 33 | 34 | 35 | 36 | 37 | 38 | org.scalaxb 39 | scalaxb-maven-plugin 40 | ${scalaxb.plugin.version} 41 | 42 | xsd 43 | ${basedir}/src/main/xsd 44 | 45 | 46 | 47 | scalaxb 48 | 49 | generate 50 | 51 | 52 | 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-source-plugin 57 | 3.3.0 58 | 59 | 60 | attach-sources 61 | 62 | jar 63 | 64 | 65 | 66 | 67 | 68 | org.codehaus.mojo 69 | build-helper-maven-plugin 70 | 3.3.0 71 | 72 | 73 | add-source 74 | generate-sources 75 | 76 | add-source 77 | 78 | 79 | 80 | ${project.build.directory}/generated-sources/scalaxb 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /xsd-scalaxb/src/main/xsd/xsd-forms.xsd: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/resources/simple.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/tree/visitor.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree 2 | 3 | import com.github.davidmoten.xsdforms.Configuration 4 | 5 | /** 6 | * ************************************************************** 7 | * 8 | * Visitor 9 | * 10 | * 11 | * ************************************************************** 12 | */ 13 | 14 | private[xsdforms] trait Visitor { 15 | import xsd._ 16 | 17 | def configuration(configuration: Configuration) 18 | def startSequence(e: Element) 19 | def endSequence 20 | def startChoice(e: Element, choice: Choice) 21 | def startChoiceItem(e: Element, p: ParticleOption, index: Int) 22 | def endChoiceItem 23 | def endChoice 24 | def simpleType(e: Element, typ: SimpleType) 25 | def baseType(e: Element, typ: BaseType) 26 | } 27 | 28 | /** 29 | * ************************************************************** 30 | * 31 | * TreeCreatingVisitor 32 | * 33 | * 34 | * ************************************************************** 35 | */ 36 | 37 | private[xsdforms] class TreeCreatingVisitor extends Visitor { 38 | import xsd._ 39 | import Util._ 40 | 41 | private var tree: Option[Node] = None 42 | var configuration: Option[Configuration] = None 43 | private val stack = new scala.collection.mutable.Stack[Node] 44 | 45 | import scala.collection.mutable.MutableList 46 | import scala.collection.mutable.HashMap 47 | 48 | private val nodes = new HashMap[Element, Node]() 49 | 50 | private implicit def wrap(e: Element): ElementWrapper = ElementWrapper(e) 51 | 52 | override def configuration(config: Configuration) { 53 | configuration = Some(config) 54 | } 55 | 56 | override def startSequence(e: Element) { 57 | val seq = NodeSequence(e, MutableList()) 58 | addChild(seq) 59 | stack.push(seq) 60 | nodes.put(e, seq) 61 | } 62 | 63 | /** 64 | * If tree is empty then sets tree to existing node. If not empty then adds node 65 | * to children of top of stack. 66 | * 67 | * @param node 68 | */ 69 | private def addChild(node: Node) { 70 | if (tree.isEmpty) tree = Some(node); 71 | else 72 | stack.top match { 73 | case g: NodeGroup => g.children += node 74 | case _ => unexpected 75 | } 76 | } 77 | 78 | override def endSequence { 79 | stack.pop 80 | } 81 | 82 | override def startChoice(e: Element, choice: Choice) { 83 | val chc = NodeChoice(e, choice, MutableList()) 84 | addChild(chc) 85 | stack.push(chc) 86 | nodes.put(e, chc) 87 | } 88 | 89 | override def startChoiceItem(e: Element, p: ParticleOption, index: Int) { 90 | // do nothing 91 | } 92 | 93 | override def endChoiceItem { 94 | //do nothing 95 | } 96 | 97 | override def endChoice { 98 | stack.pop 99 | } 100 | 101 | override def simpleType(e: Element, typ: SimpleType) { 102 | val s = NodeSimpleType(e, typ) 103 | addChild(s) 104 | nodes.put(e, s) 105 | } 106 | 107 | override def baseType(e: Element, typ: BaseType) { 108 | val s = NodeBaseType(e, typ) 109 | addChild(s) 110 | } 111 | 112 | private def toString(node: Node, margin: String): String = { 113 | node match { 114 | case NodeBaseType(e, typ) => margin + "NodeBaseType=" + e.name.get 115 | case NodeSimpleType(e, typ) => margin + "NodeSimpleType=" + e.name.get 116 | case n: NodeGroup => margin + n.getClass.getSimpleName + "=\n" + 117 | n.children.map(c => toString(c, margin + " ")).mkString("\n") 118 | case _ => unexpected 119 | } 120 | } 121 | 122 | override def toString: String = { 123 | if (tree.isEmpty) 124 | "" 125 | else 126 | toString(tree.get, "") 127 | } 128 | 129 | def rootNode: Node = tree.get; 130 | 131 | } -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/scala/com/github/davidmoten/xsdforms/generatorTest.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms { 2 | 3 | import org.junit.Test 4 | import org.junit.Before 5 | import xsd.Schema 6 | import org.junit.runners.BlockJUnit4ClassRunner 7 | import org.junit.runner.notification.Failure 8 | import java.io.File 9 | import java.io.InputStream 10 | import tree._ 11 | 12 | @Test 13 | class GeneratorTest { 14 | 15 | import org.apache.commons.io._ 16 | 17 | import TstUtil._ 18 | 19 | import java.io._ 20 | 21 | import org.junit.Assert._ 22 | 23 | @Before 24 | def testSetupWebapp() { 25 | copyHtmlJs 26 | } 27 | 28 | @Test 29 | def generatePersonForm() { 30 | println("generating person form") 31 | generate( 32 | idPrefix = "a-", 33 | schemaInputStream = TstUtil.getClass().getResourceAsStream("/test.xsd"), 34 | rootElement = "person", 35 | outputFile = new File("target/generated-webapp/person-form.html")) 36 | } 37 | 38 | @Test 39 | def generateSimpleForm() { 40 | println("generating simple form") 41 | generate( 42 | idPrefix = "a-", 43 | schemaInputStream = TstUtil.getClass().getResourceAsStream("/simple.xsd"), 44 | rootElement = "person", 45 | outputFile = new File("target/generated-webapp/simple-form.html")) 46 | } 47 | 48 | @Test 49 | def generateCensusForm { 50 | println("generating census form") 51 | generate( 52 | idPrefix = "b-", 53 | schemaInputStream = TstUtil.getClass().getResourceAsStream("/australian-census-2011.xsd"), 54 | rootElement = "census", 55 | outputFile = new File("target/generated-webapp/census-form.html")) 56 | } 57 | 58 | @Test 59 | def generatePolrepForm { 60 | println("generating polrep form") 61 | generate( 62 | idPrefix = "b-", 63 | schemaInputStream = TstUtil.getClass().getResourceAsStream("/polrep.xsd"), 64 | rootElement = "polrep", 65 | outputFile = new File("target/generated-webapp/polrep-form.html")) 66 | } 67 | 68 | @Test 69 | def generateTheAnnotationsDemoForm { 70 | println("generating the annotations demo form") 71 | generate( 72 | idPrefix = "b-", 73 | schemaInputStream = TstUtil.getClass().getResourceAsStream("/annotations-demo.xsd"), 74 | rootElement = "person", 75 | outputFile = new File("target/generated-webapp/annotations-demo.html")) 76 | } 77 | 78 | @Test 79 | def generateTheDemoForm { 80 | println("generating the demo form") 81 | generate( 82 | idPrefix = "b-", 83 | schemaInputStream = TstUtil.getClass().getResourceAsStream("/demo.xsd"), 84 | rootElement = "main", 85 | outputFile = new File("target/generated-webapp/demo-form.html")) 86 | } 87 | 88 | @Test 89 | def testGenerateZip() { 90 | val out = new File("target/out.zip") 91 | new FileOutputStream(out) 92 | Generator.generateZip(getClass.getResourceAsStream("/demo.xsd"), new FileOutputStream(out)) 93 | assertTrue(out.exists) 94 | 95 | import java.util.zip._ 96 | val zipFile = new ZipFile(out) 97 | 98 | import scala.collection.JavaConversions._ 99 | val names = enumerationAsScalaIterator(zipFile.entries()).map(_.getName).toSet 100 | println(names.mkString("\n")) 101 | assertTrue(names.contains("form.html")) 102 | assertTrue(names.contains("css/xsd-forms-style.css")) 103 | assertTrue(names.contains("js/xsd-forms-override.js")) 104 | 105 | Option.empty 106 | } 107 | 108 | @Test 109 | def testGenerateDirectory() { 110 | val out = new File("target/out.zip") 111 | val directory = new File("target/testGenerateDirectory") 112 | Generator.generateDirectory(getClass.getResourceAsStream("/demo.xsd"), directory) 113 | assertTrue(directory.exists) 114 | Option.empty 115 | } 116 | 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /xsd-scalaxb/src/main/xsd/miuml-class.xsd: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 53 | 54 | 55 | 56 | 57 | 58 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/generator.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms 2 | 3 | /** 4 | * Generates html and javascript based web forms on XML Schema (XSD). 5 | */ 6 | object `package` {} 7 | 8 | /** 9 | * Generates html and javascript based on XML schema (XSD). 10 | */ 11 | object Generator { 12 | import java.io._ 13 | import java.util.UUID 14 | import java.util.zip._ 15 | import org.apache.commons.io._ 16 | import xsd._ 17 | import tree._ 18 | 19 | /** 20 | * Using the given xml schema generates html and js files and copies 21 | * static js and css into a zipped file that is written to the given 22 | * OutputStream. The result is a standalone site for the form. 23 | * 24 | * @param schema 25 | * @param zip 26 | * @param idPrefix 27 | * @param rootElement 28 | */ 29 | def generateZip( 30 | schema: InputStream, 31 | zip: OutputStream, 32 | idPrefix: String = "a-", 33 | rootElement: Option[String] = None) { 34 | 35 | val zipOut = new ZipOutputStream(zip) 36 | 37 | def action(bytes: Array[Byte], name: String, isDirectory: Boolean) { 38 | zipOut putNextEntry new ZipEntry(name) 39 | zipOut write bytes 40 | } 41 | 42 | copyJsCssAndGeneratedForm(schema, action, idPrefix, rootElement) 43 | 44 | zipOut.close 45 | } 46 | 47 | /** 48 | * Using the given xml schema generates html and js files and copies 49 | * static js and css into the given directory. The result is a 50 | * standalone site for the form. 51 | * 52 | * @param schema 53 | * @param directory 54 | * @param idPrefix 55 | * @param rootElement 56 | */ 57 | def generateDirectory( 58 | schema: InputStream, 59 | directory: File, 60 | idPrefix: String = "a-", 61 | rootElement: Option[String] = None) { 62 | 63 | def action(bytes: Array[Byte], name: String, isDirectory: Boolean) { 64 | import org.apache.commons.io.FileUtils 65 | val path = directory.getPath + File.separator + name 66 | val file = new File(path) 67 | new File(file.getParent).mkdirs 68 | if (isDirectory) 69 | file.mkdir 70 | else { 71 | val fos = new FileOutputStream(file) 72 | fos write bytes 73 | fos.close 74 | } 75 | } 76 | 77 | copyJsCssAndGeneratedForm(schema, action, idPrefix, rootElement) 78 | } 79 | 80 | private def copyJsCssAndGeneratedForm( 81 | schema: InputStream, 82 | action: (Array[Byte], String, Boolean) => Unit, 83 | idPrefix: String = "a-", 84 | rootElement: Option[String] = None) { 85 | val text = generateHtmlAsString(schema, idPrefix, rootElement) 86 | 87 | val list = io.Source.fromInputStream(getClass.getResourceAsStream("/file-list.txt")) 88 | list.getLines.foreach { path => 89 | val bytes = IOUtils.toByteArray(getClass.getResourceAsStream("/" + path)) 90 | action(bytes, path, false) 91 | } 92 | 93 | val name = "form.html" 94 | action(text.getBytes, name, false) 95 | } 96 | 97 | /** 98 | * Using the given xml schema generates html and js into a file that 99 | * is written to the given OutputStream. 100 | * 101 | * @param schema 102 | * @param html 103 | * @param idPrefix 104 | * @param rootElement 105 | */ 106 | def generateHtml(schema: InputStream, 107 | html: OutputStream, 108 | idPrefix: String = "a-", 109 | rootElement: Option[String] = None) { 110 | 111 | val text = generateHtmlAsString(schema, idPrefix, rootElement) 112 | html write text.getBytes 113 | } 114 | 115 | /** 116 | * Returns the text of a file containing generated html and js based on 117 | * the given schema. 118 | * 119 | * @param schema 120 | * @param idPrefix 121 | * @param rootElement 122 | * @return html text including js 123 | */ 124 | def generateHtmlAsString(schema: InputStream, 125 | idPrefix: String = "a-", 126 | rootElement: Option[String] = None): String = { 127 | 128 | import scala.xml._ 129 | 130 | val schemaXb = scalaxb.fromXML[Schema]( 131 | XML.load(schema)) 132 | 133 | val ns = schemaXb.targetNamespace.get.toString 134 | 135 | val visitor = new TreeCreatingVisitor() 136 | 137 | new SchemaTraversor(schemaXb, rootElement, visitor).traverse 138 | println("tree:\n" + visitor) 139 | 140 | new FormCreator(Options(ns, Prefix(idPrefix)), 141 | visitor.configuration, 142 | visitor.rootNode).text 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /xsd-forms-html-js/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.github.davidmoten.xsdforms 5 | xsd-forms 6 | 0.2.2-SNAPSHOT 7 | 8 | xsd-forms-html-js 9 | ${project.artifactId} 10 | 11 | 12 | junit 13 | junit 14 | 4.13.2 15 | test 16 | 17 | 18 | 19 | 20 | 21 | maven-resources-plugin 22 | 3.3.1 23 | 24 | 25 | default-resources 26 | 27 | resources 28 | 29 | 30 | 31 | js 32 | css 33 | txt 34 | 35 | 36 | 37 | 38 | 39 | 40 | ${project.parent.groupId} 41 | file-list-maven-plugin 42 | ${project.parent.version} 43 | 44 | 45 | add-file-list 46 | generate-resources 47 | 48 | list 49 | 50 | 51 | ${project.build.directory}/generated-resources/file-list.txt 52 | 53 | 54 | 55 | 56 | 57 | org.codehaus.mojo 58 | build-helper-maven-plugin 59 | 3.3.0 60 | 61 | 62 | add-resources 63 | generate-resources 64 | 65 | add-resource 66 | 67 | 68 | 69 | 70 | ${project.build.directory}/generated-resources 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 84 | 85 | org.eclipse.m2e 86 | lifecycle-mapping 87 | 1.0.0 88 | 89 | 90 | 91 | 92 | 93 | com.github.davidmoten.xsdforms 94 | file-list-maven-plugin 95 | [0.1-SNAPSHOT,) 96 | 97 | list 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | org.apache.maven.plugins 107 | maven-resources-plugin 108 | [2.5,) 109 | 110 | bundle 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /xsd-forms-generator-webapp/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.github.davidmoten.xsdforms 5 | xsd-forms 6 | 0.2.2-SNAPSHOT 7 | 8 | xsd-forms-generator-webapp 9 | ${project.artifactId} 10 | war 11 | 12 | 13 | javax.servlet 14 | servlet-api 15 | 2.5 16 | provided 17 | 18 | 19 | ${project.parent.groupId} 20 | xsd-forms-generator 21 | ${project.parent.version} 22 | 23 | 24 | 25 | UTF-8 26 | 8.1.16.v20140903 27 | 9998 28 | 29 | 30 | 31 | 32 | org.mortbay.jetty 33 | jetty-maven-plugin 34 | ${jetty.plugin.version} 35 | 36 | 10 37 | foo 38 | ${jetty.stop.port} 39 | 40 | / 41 | 42 | src/main/webapp 43 | ${project.build.directory}/${project.artifactId}-${project.version} 44 | 45 | 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-dependency-plugin 51 | 3.6.0 52 | 53 | 54 | unpack 55 | generate-resources 56 | 57 | unpack 58 | 59 | 60 | 61 | 62 | ${project.parent.groupId} 63 | xsd-forms-html-js 64 | ${project.parent.version} 65 | jar 66 | true 67 | ${project.build.directory}/${project.artifactId}-${project.version} 68 | 69 | 70 | false 71 | true 72 | 73 | 74 | 75 | package 76 | copy 77 | 78 | 79 | 80 | org.eclipse.jetty 81 | jetty-runner 82 | 9.2.10.v20150310 83 | jetty-runner.jar 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | maven-site-plugin 95 | ${m3.site.version} 96 | 97 | true 98 | 99 | 100 | 102 | 103 | org.eclipse.m2e 104 | lifecycle-mapping 105 | 1.0.0 106 | 107 | 108 | 109 | 110 | 111 | 112 | org.apache.maven.plugins 113 | 114 | 115 | maven-dependency-plugin 116 | 117 | 118 | [2.8,) 119 | 120 | 121 | unpack 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | org.apache.maven.plugins 132 | 133 | 134 | maven-antrun-plugin 135 | 136 | 137 | [1.7,) 138 | 139 | 140 | run 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/resources/demo-form-expected.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | illegal characters <> 4 | default 5 | 6 | default 7 | 1 8 | 10.0435 9 | 1 10 | 123 11 | 2013-12-25 12 | 1973-06-12 13 | 22:45:00 14 | 21:55:00 15 | 2013-12-25T04:45:00 16 | 2002-05-30T09:30:00 17 | false 18 | true 19 | option-1 20 | option-1 21 | A 22 | 1.5 23 | 1 24 | A 25 | B 26 | 27 | 28 | a123 29 | 30 | a123 31 | a123 32 | AB 33 | abc 34 | 123 35 | 123 36 | 37 | 123 38 | 123 39 | 1234 40 | 1234 41 | 1234 42 | 5 43 | 5 44 | 10 45 | 10 46 | 6 47 | 5.0001 48 | 9 49 | 9.9999 50 | 51 | 1901-11-30 52 | 53 | 456 54 | 123 55 | 123 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | false 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | false 89 | 90 | 91 | 92 | 93 | 94 | false 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | false 107 | 108 | 109 | 110 | -123 111 | -1234 112 | 12 113 | 12345 114 | -12345 115 | 123456 116 | 0 117 | 118 | name1 119 | value1 120 | group1 121 | category1 122 | 123 | false 124 | true 125 | false 126 |
-------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/tree/html/html.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree.html 2 | 3 | import scala.Option.option2Iterable 4 | 5 | /** 6 | * Builds html specifically for xsd-forms. 7 | */ 8 | object `package` {} 9 | 10 | private object Html { 11 | val Legend = "legend" 12 | val Div = "div" 13 | val Select = "select" 14 | val Option = "option" 15 | val Label = "label" 16 | val Fieldset = "fieldset" 17 | val Textarea = "textarea" 18 | val Input = "input" 19 | val Id = "id" 20 | val Class = "class" 21 | val Value = "value" 22 | val Enabled = "enabled" 23 | val Checked = "checked" 24 | val Name = "name" 25 | } 26 | 27 | private[tree] class Html { 28 | import Html._ 29 | private case class HtmlElement(name: String, hasContent: Boolean) 30 | private val stack = new scala.collection.mutable.Stack[HtmlElement] 31 | //mutable! 32 | private val s = new StringBuffer 33 | //mutable! 34 | private val scriptBuffer = new StringBuffer 35 | 36 | def div(id: Option[String] = None, 37 | classes: List[String] = List(), enabledAttr: Option[String] = None, 38 | content: Option[String] = None) = 39 | element(name = Div, id = id, classes = classes, enabledAttr = enabledAttr, 40 | content = content) 41 | 42 | def select(id: Option[String] = None, name: String, 43 | classes: List[String] = List(), 44 | content: Option[String] = None, number: Option[Int] = None) = 45 | element(name = Select, id = id, classes = classes, 46 | nameAttr = Some(name), numberAttr = number, 47 | content = content) 48 | 49 | def option(id: Option[String] = None, 50 | classes: List[String] = List(), 51 | value: String, 52 | content: Option[String] = None) = 53 | element(name = Html.Option, id = id, classes = classes, 54 | content = content, value = Some(value)) 55 | 56 | def label(forInputName: String, id: Option[String] = None, 57 | classes: List[String] = List(), content: Option[String] = None) = 58 | element( 59 | name = Label, 60 | id = id, 61 | forAttr = Some(forInputName), 62 | classes = classes, 63 | content = content) 64 | 65 | def fieldset( 66 | legend: Option[String] = None, 67 | classes: List[String] = List(), 68 | id: Option[String]) = { 69 | element(name = Fieldset, classes = classes, id = id) 70 | legend match { 71 | case Some(x) => element(name = Legend, content = Some(x)).closeTag 72 | case None => 73 | } 74 | } 75 | 76 | def textarea(id: Option[String] = None, 77 | classes: List[String] = List(), 78 | content: Option[String] = None, 79 | value: Option[String] = None, 80 | name: String, number: Option[Int] = None, 81 | closed: Boolean = false) = 82 | element(name = Textarea, 83 | id = id, 84 | classes = classes, 85 | content = content, 86 | value = value, 87 | nameAttr = Some(name), 88 | numberAttr = number) 89 | 90 | def input(id: Option[String] = None, 91 | classes: List[String] = List(), 92 | content: Option[String] = None, 93 | name: String, value: Option[String] = None, 94 | checked: Option[Boolean] = None, 95 | number: Option[Int] = None, 96 | typ: Option[String]) = 97 | element(name = Input, id = id, classes = classes, checked = checked, 98 | content = content, value = value, 99 | nameAttr = Some(name), typ = typ, numberAttr = number) 100 | 101 | private def classNames(classes: List[String]) = 102 | if (classes.length == 0) 103 | None 104 | else 105 | Some(classes.mkString(" ")) 106 | 107 | private def element(name: String, 108 | id: Option[String] = None, 109 | classes: List[String] = List(), 110 | content: Option[String] = None, 111 | value: Option[String] = None, 112 | checked: Option[Boolean] = None, 113 | nameAttr: Option[String] = None, 114 | enabledAttr: Option[String] = None, 115 | forAttr: Option[String] = None, 116 | numberAttr: Option[Int] = None, 117 | typ: Option[String] = None): Html = { 118 | val attributes = 119 | id.map((Id, _)) ++ 120 | classNames(classes).map((Class -> _)) ++ 121 | value.map((Value, _)) ++ 122 | nameAttr.map((Name, _)) ++ 123 | enabledAttr.map((Enabled, _)) ++ 124 | forAttr.map(("for", _)) ++ 125 | typ.map(("type", _)) ++ 126 | checked.map(x => (Checked, x.toString)) ++ 127 | numberAttr.map(x => ("number", x.toString)) 128 | elementBase(name, attributes.toMap, content) 129 | this 130 | } 131 | 132 | private def elementBase(name: String, attributes: Map[String, String], 133 | content: Option[String]): Html = { 134 | stack.push(HtmlElement(name, content.isDefined)) 135 | indent 136 | val attributesClause = 137 | attributes.map(x => x._1 + "=\"" + x._2 + "\"").mkString(" ") 138 | append("<" + name + " " 139 | + attributesClause + ">" + content.mkString) 140 | this 141 | } 142 | 143 | private def indent { 144 | val indent = " " * stack.size 145 | append("\n") 146 | append(indent) 147 | } 148 | 149 | private def append(str: String) = { 150 | s.append(str) 151 | this 152 | } 153 | 154 | def closeTag: Html = { 155 | if (stack.isEmpty) 156 | throw new RuntimeException("closeTag called on empty html stack! html so far=\n" + s.toString) 157 | val element = stack.head 158 | if (!element.hasContent) { 159 | indent 160 | } 161 | append(""); 162 | stack.pop 163 | this 164 | } 165 | 166 | def closeTag(n: Int): Html = { 167 | for (i <- 1 to n) 168 | closeTag 169 | this 170 | } 171 | 172 | def appendScript(s: String) { 173 | scriptBuffer append s 174 | } 175 | 176 | def script = scriptBuffer.toString 177 | 178 | override def toString = s.toString 179 | 180 | } 181 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/presentation/annotation.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.presentation 2 | 3 | import xsd.Annotatedable 4 | 5 | /** 6 | * Configures presentation of web forms generated by xsd-forms. 7 | */ 8 | object `package` {} 9 | 10 | private[xsdforms] object Annotation { 11 | //TODO document each of the annotations in scaladoc 12 | 13 | /** 14 | * Annotation 'label' is the label to be used for the element 15 | * input field. Usually located just left of the input field 16 | * associated with the element with this annotation. If omitted 17 | * the default value is the element name with dashes and underscores 18 | * replaced with spaces then camel cased. 19 | */ 20 | val Label = XsdFormsAnnotation("label") 21 | 22 | /** 23 | * Annotation 'choice' If choice=inline then choice is inline 24 | * with radio selector otherwise appears after the group of 25 | * radio selectors. 26 | */ 27 | val Choice = XsdFormsAnnotation("choice") 28 | 29 | /** 30 | * For a radio selector, choice label will go against the selector. 31 | * Use 'label' against the element itself (which will be made 32 | * visible by the selector). 33 | */ 34 | val ChoiceLabel = XsdFormsAnnotation("choiceLabel") 35 | 36 | /** 37 | * If legend is set then is used as label for a fieldset block. 38 | */ 39 | val Legend = XsdFormsAnnotation("legend") 40 | 41 | /** 42 | * 'repeatLabel' is the text on the button that when pressed 43 | * creates another instance of the element or complexType at 44 | * that level. The default is '+'. 45 | */ 46 | val RepeatLabel = XsdFormsAnnotation("repeatLabel") 47 | 48 | /** 49 | * 'minOccursZeroLabel' is the button label when a sequence of 50 | * elements (a complex type) has minOccurs="0". Clicking the 51 | * minOccursZero button toggles the visiblity of the sequence. 52 | */ 53 | val MinOccursZeroLabel = XsdFormsAnnotation("minOccursZeroLabel") 54 | 55 | /** 56 | * 'removeLabel' is the text on the button that when pressed 57 | * removes the current instance of the element or complexType. 58 | * The default is '-'. 59 | */ 60 | val RemoveLabel = XsdFormsAnnotation("removeLabel") 61 | 62 | /** 63 | * 'title' is for the text to be used as the title for an element. 64 | */ 65 | val Title = XsdFormsAnnotation("title") 66 | 67 | /** 68 | * 'before' is the text to appear before an element. 69 | */ 70 | val Before = XsdFormsAnnotation("before") 71 | 72 | /** 73 | * 'after' is the text to appear after an element. 74 | */ 75 | val After = XsdFormsAnnotation("after") 76 | 77 | /** 78 | * if text=textarea then html textarea used as input. Otherwise normal 79 | * short text input used. 80 | */ 81 | val Text = XsdFormsAnnotation("text") 82 | 83 | /** 84 | * Specific css for width to be applied to the input element. 85 | */ 86 | val Width = XsdFormsAnnotation("width") 87 | 88 | /** 89 | * If selector=radio then radio control used for choice instead 90 | * of drop down. 91 | */ 92 | val Selector = XsdFormsAnnotation("selector") 93 | 94 | /** 95 | * If addBlank=true and an enumeration is being displayed (in a 96 | * drop-down) then a blank option will be added to the drop-down 97 | * representing no selection. 98 | */ 99 | val AddBlank = XsdFormsAnnotation("addBlank") 100 | 101 | /** 102 | * 'css' can be set to a group of css styles which will be applied to 103 | * the element. For example 'width:20em;font-size:80%'. 104 | */ 105 | val Css = XsdFormsAnnotation("css") 106 | 107 | /** 108 | * Validation message to be displayed if the input is assessed 109 | * as invalid. 110 | */ 111 | val Validation = XsdFormsAnnotation("validation") 112 | 113 | /** 114 | * Help to display as tooltip if user clicks/hovers input. Not a 115 | * great way of displaying help as it hides whatever is underneath 116 | * it even if temporarily. 117 | */ 118 | val Help = XsdFormsAnnotation("help") 119 | 120 | /** 121 | * On a named element with an enumeration type, set annotation 122 | * {{{ 123 | * makeVisible="value1->n1,value2->n2" 124 | * }}} 125 | * where value1,value2 are enumerated values and n1,n2 integers are the relative 126 | * indexes (1 equates to the following element at the same level) of the element 127 | * that is to be made visible on selection of that value. 128 | * You can also set makeVisible on a specific member of the enumeration using 129 | * {{{ 130 | * makeVisible="n"" 131 | * }}}where n is an integer only. 132 | * 133 | * The element that is to be made visible should be annotated with visible='false'. 134 | * 135 | * Make sure you set minOccurs=0 on the element that may be invisible. 136 | * 137 | * This annotation also works with boolean types. Use 138 | * {{{ 139 | * makeVisible="true->1" 140 | * }}} 141 | * to make the following element become visible when ticked (and invisible when unticked). 142 | */ 143 | val MakeVisible = XsdFormsAnnotation("makeVisible") 144 | 145 | /** 146 | * 'nonRepeatingTitle' is the title displayed after 'title' for a complexType 147 | * that has maxOccurs > 1. 148 | */ 149 | val NonRepeatingTitle = XsdFormsAnnotation("nonRepeatingTitle") 150 | 151 | /** 152 | * Annotation 'description' appears just below the input box. 153 | */ 154 | val Description = XsdFormsAnnotation("description") 155 | 156 | /** 157 | * 'visible' = false will hide the element at first. This is most 158 | * useful in conjunction with 'makeVisible'. 159 | */ 160 | val Visible = XsdFormsAnnotation("visible") 161 | 162 | /** 163 | * 'maxRepeats' should be an integer value >0 for an element and is the 164 | * maximum number of repeats generated in html of the element (all 165 | * be them hidden). 166 | */ 167 | val MaxRepeats = XsdFormsAnnotation("maxRepeats") 168 | 169 | val Header = XsdFormsAnnotation("header") 170 | 171 | val Footer = XsdFormsAnnotation("footer") 172 | val ExtraCss = XsdFormsAnnotation("extraCss") 173 | val ExtraImports = XsdFormsAnnotation("extraImports") 174 | val ExtraScript = XsdFormsAnnotation("extraScript") 175 | } 176 | 177 | private[xsdforms] case class XsdFormsAnnotation(name: String) { 178 | //TODO move dep to a util package 179 | import com.github.davidmoten.xsdforms.tree.XsdUtil 180 | 181 | def from(a:Annotatedable) = a.annotation match { 182 | case Some(x) => 183 | x.attributes.get("@{" + XsdUtil.AppInfoSchema + "}" + name) match { 184 | case Some(y) => Some(y.value.toString) 185 | case None => None 186 | } 187 | case None => None 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /xsd-forms-generator/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.github.davidmoten.xsdforms 5 | xsd-forms 6 | 0.2.2-SNAPSHOT 7 | 8 | xsd-forms-generator 9 | ${project.artifactId} 10 | 11 | 2.53.1 12 | /usr/local/bin/chromedriver 13 | 3.3 14 | 2.6 15 | 16 | 17 | 18 | selenium 19 | 20 | 21 | selenium 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | default 31 | 32 | 33 | selenium 34 | !true 35 | 36 | 37 | 38 | **/*SeleniumTest.* 39 | 40 | 41 | 42 | 43 | 44 | ${project.parent.groupId} 45 | xsd-scalaxb 46 | ${project.parent.version} 47 | 48 | 49 | ${project.parent.groupId} 50 | xsd-forms-html-js 51 | ${project.parent.version} 52 | 53 | 54 | commons-io 55 | commons-io 56 | 2.13.0 57 | 58 | 59 | 60 | 61 | junit 62 | junit 63 | 4.13.2 64 | test 65 | 66 | 67 | ${project.parent.groupId} 68 | demo-scalaxb 69 | ${project.parent.version} 70 | test 71 | 72 | 73 | org.seleniumhq.selenium 74 | selenium-server 75 | ${selenium.version} 76 | test 77 | 78 | 79 | org.seleniumhq.selenium 80 | selenium-java 81 | ${selenium.version} 82 | pom 83 | test 84 | 85 | 91 | 92 | 93 | src/main/scala 94 | src/test/scala 95 | 96 | 97 | net.alchim31.maven 98 | scala-maven-plugin 99 | ${scala.plugin.version} 100 | 101 | 102 | 103 | compile 104 | testCompile 105 | 106 | 107 | 108 | -deprecation 109 | -dependencyfile 110 | ${project.build.directory}/.scala_dependencies 111 | 112 | 113 | 114 | 115 | 116 | 117 | org.apache.maven.plugins 118 | maven-surefire-plugin 119 | 3.1.2 120 | 121 | false 122 | true 123 | 124 | 125 | 126 | **/*Test.* 127 | **/*Suite.* 128 | 129 | 130 | ${surefire.excludes} 131 | 132 | -Dwebdriver.chrome.driver=${webdriver.chrome.driver} 133 | 134 | 135 | 136 | org.codehaus.mojo 137 | build-helper-maven-plugin 138 | 3.3.0 139 | 140 | 141 | add-resource 142 | generate-resources 143 | 144 | add-resource 145 | 146 | 147 | 148 | 149 | ${project.build.directory}/generated-resources 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | org.apache.maven.plugins 159 | maven-source-plugin 160 | 3.3.0 161 | 162 | 163 | attach-sources 164 | 165 | jar 166 | 167 | 168 | 169 | 170 | 171 | org.mortbay.jetty 172 | jetty-maven-plugin 173 | 8.1.16.v20140903 174 | 175 | 0 176 | 177 | / 178 | 179 | src/main/webapp,target/generated-webapp 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/resources/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 220 | 221 | 222 | 223 |
224 | 225 |
226 |
227 | 228 | 229 | 230 |
The form is not yet complete. Check through the form for error messages
231 |
Submit
232 |

233 | 234 |
235 | 236 |
237 | 238 | 239 | -------------------------------------------------------------------------------- /xsd-scalaxb/src/main/xsd/datatypes.dtd: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 81 | 82 | 83 | 84 | 85 | 86 | 89 | 90 | 93 | 94 | 95 | 97 | 102 | 103 | 107 | 111 | 120 | 121 | 125 | 129 | 130 | 134 | 138 | 139 | 140 | 144 | 145 | 149 | 150 | 151 | 155 | 156 | 160 | 161 | 162 | 166 | 167 | 171 | 172 | 173 | 177 | 178 | 182 | 183 | 187 | 188 | 189 | 190 | 193 | 194 | 195 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/css/xsd-forms-style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0 0px; 3 | font: normal 62.5% "Lucida Grande", Helvetica, Verdana, Arial; 4 | background-color: #F5F5F5 ;/*#EDFAD9;*/ 5 | } 6 | 7 | .clear { 8 | clear:left; 9 | } 10 | 11 | .form { 12 | margin-left: 0px; 13 | max-width: 100%; 14 | } 15 | 16 | .sequence { 17 | clear:left; 18 | } 19 | 20 | .sequence-content { 21 | margin-left: 10px; 22 | } 23 | 24 | .item-title { 25 | clear:left; 26 | font-weight:bold; 27 | margin-top:10px; 28 | margin-left:10px; 29 | } 30 | 31 | .item-before { 32 | clear:left; 33 | margin-top:10px; 34 | margin-left:15px; 35 | padding-bottom:7px; 36 | } 37 | 38 | .item-after { 39 | margin-bottom:10px; 40 | margin-left:15px; 41 | } 42 | 43 | .item { 44 | clear: left; 45 | border-top: 1px solid #C9DCA6; 46 | color: black; 47 | } 48 | 49 | .sequence-number { 50 | padding-top: 13px; 51 | padding-left: 5px; 52 | padding-right: 5px; 53 | width: 2em; 54 | color: gray; 55 | font-size: 52%; 56 | } 57 | 58 | .sequence-label { 59 | margin-top: 10px; 60 | min-width: 100px; 61 | padding-right: 10px; 62 | padding-bottom: 10px; 63 | font-weight: bold; 64 | margin-left:10px; 65 | } 66 | 67 | .choice { 68 | clear:left; 69 | margin-left:10px; 70 | } 71 | 72 | .choice-number { 73 | padding-top: 13px; 74 | padding-left: 5px; 75 | padding-right: 5px; 76 | width: 2em; 77 | color: gray; 78 | font-size: 52%; 79 | } 80 | 81 | .choice-label { 82 | margin-top: 10px; 83 | min-width: 100px; 84 | padding-right: 10px; 85 | padding-bottom: 10px; 86 | font-weight: bold; 87 | } 88 | 89 | .choice-content { 90 | 91 | } 92 | 93 | .choice-item { 94 | /* float:left; */ 95 | } 96 | 97 | .item-enclosing { 98 | padding-top:7px; 99 | clear:left; 100 | } 101 | 102 | .item-number { 103 | clear:left; 104 | padding-top: 5px; 105 | padding-left: 5px; 106 | padding-right: 5px; 107 | float: left; 108 | width: 2em; 109 | color: gray; 110 | font-size: 72%; 111 | } 112 | 113 | .item-label { 114 | float: left; 115 | min-width: 100px; 116 | padding-right: 10px; 117 | /** padding-bottom: 10px;**/ 118 | padding-top: 4px; 119 | 120 | } 121 | 122 | .item-path { 123 | display:none; 124 | } 125 | 126 | .select { 127 | font-size:100%; 128 | height:20px; 129 | margin-top: 7 px; 130 | margin-bottom: 7 px; 131 | } 132 | 133 | .item-input { 134 | float:left; 135 | } 136 | 137 | .item-input-text { 138 | clear: left; 139 | /* border: #999999 solid thin; 140 | margin-top: 7 px; 141 | */ 142 | margin-bottom: 5px; 143 | height:20px; 144 | font-size:100%; 145 | } 146 | 147 | .item-input-textarea { 148 | clear: left; 149 | height: 6em; 150 | width: 25em; 151 | margin-top: 7px; 152 | margin-bottom: 7px; 153 | overflow:auto; 154 | font-size:120%; 155 | } 156 | 157 | .item-description { 158 | margin-left:4em; 159 | margin-bottom:10px; 160 | font-size:85%; 161 | } 162 | 163 | .item-error { 164 | margin-left:0px; 165 | margin-bottom:10px; 166 | margin-top:5px; 167 | max-width:250px; 168 | padding:10px; 169 | font-size:85%; 170 | font-weight:bold; 171 | color:white; 172 | background-color:red; 173 | display: none; 174 | } 175 | 176 | .validationErrors { 177 | background-color:red; 178 | color:white; 179 | font-size:100%; 180 | font-weight: bold; 181 | margin-bottom:10px; 182 | margin-top: 10px; 183 | padding: 10px; 184 | max-width:200px; 185 | display: none; 186 | } 187 | 188 | .non-repeating-title { 189 | font-weight: bold; 190 | clear:left; 191 | margin-left:10px; 192 | padding-top:3px; 193 | margin-top:5px; 194 | } 195 | 196 | .repeating-enclosing { 197 | overflow:hidden; 198 | width:100%; 199 | } 200 | 201 | .repeat-button { 202 | /* display: inline-block; */ 203 | /* zoom: 1; */ /* zoom and *display = ie7 hack for display:inline-block */ 204 | /* display: inline; */ 205 | clear:left; 206 | float:left; 207 | vertical-align: baseline; 208 | margin: 5px 20% 10px 0px; 209 | outline: none; 210 | cursor: pointer; 211 | text-align: center; 212 | text-decoration: none; 213 | font: 11px/100% Arial, Helvetica, sans-serif; 214 | padding: .5em 2em .55em 2em; 215 | text-shadow: 0 1px 1px rgba(0,0,0,.3); 216 | -webkit-border-radius: .5em; 217 | -moz-border-radius: .5em; 218 | border-radius: .5em; 219 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2); 220 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2); 221 | box-shadow: 0 1px 2px rgba(0,0,0,.2); 222 | } 223 | .repeat-button:hover { 224 | text-decoration: none; 225 | } 226 | .repeat-button:active { 227 | position: relative; 228 | top: 1px; 229 | } 230 | 231 | .remove-button-container { 232 | overflow:hidden; 233 | width:100%; 234 | } 235 | 236 | .remove-button { 237 | clear:left; 238 | float:left; 239 | vertical-align: baseline; 240 | margin: 5px 20% 10px 50px; 241 | outline: none; 242 | cursor: pointer; 243 | text-align: center; 244 | text-decoration: none; 245 | font: 11px/100% Arial, Helvetica, sans-serif; 246 | padding: .5em 2em .55em 2em; 247 | text-shadow: 0 1px 1px rgba(0,0,0,.3); 248 | -webkit-border-radius: .5em; 249 | -moz-border-radius: .5em; 250 | border-radius: .5em; 251 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2); 252 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2); 253 | box-shadow: 0 1px 2px rgba(0,0,0,.2); 254 | } 255 | .remove-button:hover { 256 | text-decoration: none; 257 | } 258 | .remove-button:active { 259 | position: relative; 260 | top: 1px; 261 | } 262 | 263 | .item-add { 264 | display: inline-block; 265 | zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */ 266 | display: inline; 267 | vertical-align: baseline; 268 | margin: 0 2px; 269 | outline: none; 270 | cursor: pointer; 271 | text-align: center; 272 | text-decoration: none; 273 | font: 11px/100% Arial, Helvetica, sans-serif; 274 | padding: .5em 2em .55em; 275 | text-shadow: 0 1px 1px rgba(0,0,0,.3); 276 | -webkit-border-radius: .5em; 277 | -moz-border-radius: .5em; 278 | border-radius: .5em; 279 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2); 280 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2); 281 | box-shadow: 0 1px 2px rgba(0,0,0,.2); 282 | } 283 | .item-add:hover { 284 | text-decoration: none; 285 | } 286 | .item-add:active { 287 | position: relative; 288 | top: 1px; 289 | } 290 | 291 | .group-add { 292 | /* display: inline-block; */ 293 | /* zoom: 1; */ /* zoom and *display = ie7 hack for display:inline-block */ 294 | /* display: inline; */ 295 | vertical-align: baseline; 296 | margin: 0px 20% 10px 20%; 297 | outline: none; 298 | cursor: pointer; 299 | text-align: center; 300 | text-decoration: none; 301 | font: 11px/100% Arial, Helvetica, sans-serif; 302 | padding: .5em 2em .55em 2em; 303 | text-shadow: 0 1px 1px rgba(0,0,0,.3); 304 | -webkit-border-radius: .5em; 305 | -moz-border-radius: .5em; 306 | border-radius: .5em; 307 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2); 308 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2); 309 | box-shadow: 0 1px 2px rgba(0,0,0,.2); 310 | } 311 | .group-add:hover { 312 | text-decoration: none; 313 | } 314 | .group-add:active { 315 | position: relative; 316 | top: 1px; 317 | } 318 | 319 | #submit { 320 | border: #999999 solid thin; 321 | width: 6em; 322 | text-align: center; 323 | margin-left: 20px; 324 | margin-top:20px; 325 | padding:5px; 326 | background:white; 327 | } 328 | 329 | .invisible { 330 | display:none; 331 | } 332 | 333 | .bigrounded { 334 | -webkit-border-radius: 2em; 335 | -moz-border-radius: 2em; 336 | border-radius: 2em; 337 | } 338 | .medium { 339 | font-size: 12px; 340 | padding: .4em 1.5em .42em; 341 | } 342 | .small { 343 | font-size: 11px; 344 | padding: .2em 1em .275em; 345 | } 346 | 347 | /* white */ 348 | .white { 349 | color: #606060; 350 | border: solid 1px #b7b7b7; 351 | background: #fff; 352 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed)); 353 | background: -moz-linear-gradient(top, #fff, #ededed); 354 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed'); 355 | } 356 | .white:hover { 357 | background: #ededed; 358 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc)); 359 | background: -moz-linear-gradient(top, #fff, #dcdcdc); 360 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc'); 361 | } 362 | .white:active { 363 | color: #999; 364 | background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff)); 365 | background: -moz-linear-gradient(top, #ededed, #fff); 366 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff'); 367 | } 368 | 369 | 370 | em { 371 | color: red; 372 | } 373 | 374 | .failure { 375 | color:red; 376 | font-size: 150%; 377 | } 378 | 379 | 380 | .min-occurs-zero { 381 | float:left; 382 | } 383 | 384 | .min-occurs-zero-container { 385 | overflow:hidden; 386 | width: 100%; 387 | margin-top: 0.5em; 388 | margin-left: 1em; 389 | } 390 | 391 | .min-occurs-zero-label { 392 | float:left; 393 | margin-right:1em; 394 | } 395 | 396 | .clr { 397 | clear:left; 398 | } 399 | -------------------------------------------------------------------------------- /xsd-forms-html-js/src/main/resources/css/xsd-forms-style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0 0px; 3 | font: normal 62.5% "Lucida Grande", Helvetica, Verdana, Arial; 4 | background-color: #F5F5F5 ;/*#EDFAD9;*/ 5 | } 6 | 7 | .clear { 8 | clear:left; 9 | } 10 | 11 | .form { 12 | margin-left: 0px; 13 | max-width: 100%; 14 | } 15 | 16 | .sequence { 17 | clear:left; 18 | } 19 | 20 | .sequence-content { 21 | margin-left: 10px; 22 | } 23 | 24 | .item-title { 25 | clear:left; 26 | font-weight:bold; 27 | margin-top:10px; 28 | margin-left:10px; 29 | } 30 | 31 | .item-before { 32 | clear:left; 33 | margin-top:10px; 34 | margin-left:15px; 35 | padding-bottom:7px; 36 | } 37 | 38 | .item-after { 39 | margin-bottom:10px; 40 | margin-left:15px; 41 | } 42 | 43 | .item { 44 | clear: left; 45 | border-top: 1px solid #C9DCA6; 46 | color: black; 47 | } 48 | 49 | .sequence-number { 50 | padding-top: 13px; 51 | padding-left: 5px; 52 | padding-right: 5px; 53 | width: 2em; 54 | color: gray; 55 | font-size: 52%; 56 | } 57 | 58 | .sequence-label { 59 | margin-top: 10px; 60 | min-width: 100px; 61 | padding-right: 10px; 62 | padding-bottom: 10px; 63 | font-weight: bold; 64 | margin-left:10px; 65 | } 66 | 67 | .choice { 68 | clear:left; 69 | margin-left:10px; 70 | } 71 | 72 | .choice-number { 73 | padding-top: 13px; 74 | padding-left: 5px; 75 | padding-right: 5px; 76 | width: 2em; 77 | color: gray; 78 | font-size: 52%; 79 | } 80 | 81 | .choice-label { 82 | margin-top: 10px; 83 | min-width: 100px; 84 | padding-right: 10px; 85 | padding-bottom: 10px; 86 | font-weight: bold; 87 | } 88 | 89 | .choice-content { 90 | 91 | } 92 | 93 | .choice-item { 94 | /* float:left; */ 95 | } 96 | 97 | .item-enclosing { 98 | padding-top:7px; 99 | clear:left; 100 | } 101 | 102 | .item-number { 103 | clear:left; 104 | padding-top: 5px; 105 | padding-left: 5px; 106 | padding-right: 5px; 107 | float: left; 108 | width: 2em; 109 | color: gray; 110 | font-size: 72%; 111 | } 112 | 113 | .item-label { 114 | float: left; 115 | min-width: 100px; 116 | padding-right: 10px; 117 | /** padding-bottom: 10px;**/ 118 | padding-top: 4px; 119 | 120 | } 121 | 122 | .item-path { 123 | display:none; 124 | } 125 | 126 | .select { 127 | font-size:100%; 128 | height:20px; 129 | margin-top: 7 px; 130 | margin-bottom: 7 px; 131 | } 132 | 133 | .item-input { 134 | float:left; 135 | } 136 | 137 | .item-input-text { 138 | clear: left; 139 | /* border: #999999 solid thin; 140 | margin-top: 7 px; 141 | */ 142 | margin-bottom: 5px; 143 | height:20px; 144 | font-size:100%; 145 | } 146 | 147 | .item-input-textarea { 148 | clear: left; 149 | height: 6em; 150 | width: 25em; 151 | margin-top: 7px; 152 | margin-bottom: 7px; 153 | overflow:auto; 154 | font-size:120%; 155 | } 156 | 157 | .item-description { 158 | margin-left:4em; 159 | margin-bottom:10px; 160 | font-size:85%; 161 | } 162 | 163 | .item-error { 164 | margin-left:0px; 165 | margin-bottom:10px; 166 | margin-top:5px; 167 | max-width:250px; 168 | padding:10px; 169 | font-size:85%; 170 | font-weight:bold; 171 | color:white; 172 | background-color:red; 173 | display: none; 174 | } 175 | 176 | .validationErrors { 177 | background-color:red; 178 | color:white; 179 | font-size:100%; 180 | font-weight: bold; 181 | margin-bottom:10px; 182 | margin-top: 10px; 183 | padding: 10px; 184 | max-width:200px; 185 | display: none; 186 | } 187 | 188 | .non-repeating-title { 189 | font-weight: bold; 190 | clear:left; 191 | margin-left:10px; 192 | padding-top:3px; 193 | margin-top:5px; 194 | } 195 | 196 | .repeating-enclosing { 197 | overflow:hidden; 198 | width:100%; 199 | } 200 | 201 | .repeat-button { 202 | /* display: inline-block; */ 203 | /* zoom: 1; */ /* zoom and *display = ie7 hack for display:inline-block */ 204 | /* display: inline; */ 205 | clear:left; 206 | float:left; 207 | vertical-align: baseline; 208 | margin: 5px 20% 10px 0px; 209 | outline: none; 210 | cursor: pointer; 211 | text-align: center; 212 | text-decoration: none; 213 | font: 11px/100% Arial, Helvetica, sans-serif; 214 | padding: .5em 2em .55em 2em; 215 | text-shadow: 0 1px 1px rgba(0,0,0,.3); 216 | -webkit-border-radius: .5em; 217 | -moz-border-radius: .5em; 218 | border-radius: .5em; 219 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2); 220 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2); 221 | box-shadow: 0 1px 2px rgba(0,0,0,.2); 222 | } 223 | .repeat-button:hover { 224 | text-decoration: none; 225 | } 226 | .repeat-button:active { 227 | position: relative; 228 | top: 1px; 229 | } 230 | 231 | .remove-button-container { 232 | overflow:hidden; 233 | width:100%; 234 | } 235 | 236 | .remove-button { 237 | clear:left; 238 | float:left; 239 | vertical-align: baseline; 240 | margin: 5px 20% 10px 50px; 241 | outline: none; 242 | cursor: pointer; 243 | text-align: center; 244 | text-decoration: none; 245 | font: 11px/100% Arial, Helvetica, sans-serif; 246 | padding: .5em 2em .55em 2em; 247 | text-shadow: 0 1px 1px rgba(0,0,0,.3); 248 | -webkit-border-radius: .5em; 249 | -moz-border-radius: .5em; 250 | border-radius: .5em; 251 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2); 252 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2); 253 | box-shadow: 0 1px 2px rgba(0,0,0,.2); 254 | } 255 | .remove-button:hover { 256 | text-decoration: none; 257 | } 258 | .remove-button:active { 259 | position: relative; 260 | top: 1px; 261 | } 262 | 263 | .item-add { 264 | display: inline-block; 265 | zoom: 1; /* zoom and *display = ie7 hack for display:inline-block */ 266 | display: inline; 267 | vertical-align: baseline; 268 | margin: 0 2px; 269 | outline: none; 270 | cursor: pointer; 271 | text-align: center; 272 | text-decoration: none; 273 | font: 11px/100% Arial, Helvetica, sans-serif; 274 | padding: .5em 2em .55em; 275 | text-shadow: 0 1px 1px rgba(0,0,0,.3); 276 | -webkit-border-radius: .5em; 277 | -moz-border-radius: .5em; 278 | border-radius: .5em; 279 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2); 280 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2); 281 | box-shadow: 0 1px 2px rgba(0,0,0,.2); 282 | } 283 | .item-add:hover { 284 | text-decoration: none; 285 | } 286 | .item-add:active { 287 | position: relative; 288 | top: 1px; 289 | } 290 | 291 | .group-add { 292 | /* display: inline-block; */ 293 | /* zoom: 1; */ /* zoom and *display = ie7 hack for display:inline-block */ 294 | /* display: inline; */ 295 | vertical-align: baseline; 296 | margin: 0px 20% 10px 20%; 297 | outline: none; 298 | cursor: pointer; 299 | text-align: center; 300 | text-decoration: none; 301 | font: 11px/100% Arial, Helvetica, sans-serif; 302 | padding: .5em 2em .55em 2em; 303 | text-shadow: 0 1px 1px rgba(0,0,0,.3); 304 | -webkit-border-radius: .5em; 305 | -moz-border-radius: .5em; 306 | border-radius: .5em; 307 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2); 308 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.2); 309 | box-shadow: 0 1px 2px rgba(0,0,0,.2); 310 | } 311 | .group-add:hover { 312 | text-decoration: none; 313 | } 314 | .group-add:active { 315 | position: relative; 316 | top: 1px; 317 | } 318 | 319 | #submit { 320 | border: #999999 solid thin; 321 | width: 6em; 322 | text-align: center; 323 | margin-left: 20px; 324 | margin-top:20px; 325 | padding:5px; 326 | background:white; 327 | } 328 | 329 | .invisible { 330 | display:none; 331 | } 332 | 333 | .bigrounded { 334 | -webkit-border-radius: 2em; 335 | -moz-border-radius: 2em; 336 | border-radius: 2em; 337 | } 338 | .medium { 339 | font-size: 12px; 340 | padding: .4em 1.5em .42em; 341 | } 342 | .small { 343 | font-size: 11px; 344 | padding: .2em 1em .275em; 345 | } 346 | 347 | /* white */ 348 | .white { 349 | color: #606060; 350 | border: solid 1px #b7b7b7; 351 | background: #fff; 352 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed)); 353 | background: -moz-linear-gradient(top, #fff, #ededed); 354 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed'); 355 | } 356 | .white:hover { 357 | background: #ededed; 358 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc)); 359 | background: -moz-linear-gradient(top, #fff, #dcdcdc); 360 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc'); 361 | } 362 | .white:active { 363 | color: #999; 364 | background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff)); 365 | background: -moz-linear-gradient(top, #ededed, #fff); 366 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff'); 367 | } 368 | 369 | 370 | em { 371 | color: red; 372 | } 373 | 374 | .failure { 375 | color:red; 376 | font-size: 150%; 377 | } 378 | 379 | 380 | .min-occurs-zero { 381 | float:left; 382 | } 383 | 384 | .min-occurs-zero-container { 385 | overflow:hidden; 386 | width: 100%; 387 | margin-top: 0.5em; 388 | margin-left: 1em; 389 | } 390 | 391 | .min-occurs-zero-label { 392 | float:left; 393 | margin-right:1em; 394 | } 395 | 396 | .clr { 397 | clear:left; 398 | } 399 | -------------------------------------------------------------------------------- /xsd-scalaxb/src/main/xsd/xml.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 |
11 |

About the XML namespace

12 | 13 |
14 |

15 | This schema document describes the XML namespace, in a form 16 | suitable for import by other schema documents. 17 |

18 |

19 | See 20 | http://www.w3.org/XML/1998/namespace.html and 21 | 22 | http://www.w3.org/TR/REC-xml for information 23 | about this namespace. 24 |

25 |

26 | Note that local names in this namespace are intended to be 27 | defined only by the World Wide Web Consortium or its subgroups. 28 | The names currently defined in this namespace are listed below. 29 | They should not be used with conflicting semantics by any Working 30 | Group, specification, or document instance. 31 |

32 |

33 | See further below in this document for more information about how to refer to this schema document from your own 35 | XSD schema documents and about the 36 | namespace-versioning policy governing this schema document. 37 |

38 |
39 |
40 |
41 |
42 | 43 | 44 | 45 | 46 |
47 | 48 |

lang (as an attribute name)

49 |

50 | denotes an attribute whose value 51 | is a language code for the natural language of the content of 52 | any element; its value is inherited. This name is reserved 53 | by virtue of its definition in the XML specification.

54 | 55 |
56 |
57 |

Notes

58 |

59 | Attempting to install the relevant ISO 2- and 3-letter 60 | codes as the enumerated possible values is probably never 61 | going to be a realistic possibility. 62 |

63 |

64 | See BCP 47 at 65 | http://www.rfc-editor.org/rfc/bcp/bcp47.txt 66 | and the IANA language subtag registry at 67 | 68 | http://www.iana.org/assignments/language-subtag-registry 69 | for further information. 70 |

71 |

72 | The union allows for the 'un-declaration' of xml:lang with 73 | the empty string. 74 |

75 |
76 |
77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 |
88 | 89 | 90 | 91 | 92 |
93 | 94 |

space (as an attribute name)

95 |

96 | denotes an attribute whose 97 | value is a keyword indicating what whitespace processing 98 | discipline is intended for the content of the element; its 99 | value is inherited. This name is reserved by virtue of its 100 | definition in the XML specification.

101 | 102 |
103 |
104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 |
116 | 117 |

base (as an attribute name)

118 |

119 | denotes an attribute whose value 120 | provides a URI to be used as the base for interpreting any 121 | relative URIs in the scope of the element on which it 122 | appears; its value is inherited. This name is reserved 123 | by virtue of its definition in the XML Base specification.

124 | 125 |

126 | See http://www.w3.org/TR/xmlbase/ 128 | for information about this attribute. 129 |

130 |
131 |
132 |
133 |
134 | 135 | 136 | 137 | 138 |
139 | 140 |

id (as an attribute name)

141 |

142 | denotes an attribute whose value 143 | should be interpreted as if declared to be of type ID. 144 | This name is reserved by virtue of its definition in the 145 | xml:id specification.

146 | 147 |

148 | See http://www.w3.org/TR/xml-id/ 150 | for information about this attribute. 151 |

152 |
153 |
154 |
155 |
156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 |
167 | 168 |

Father (in any context at all)

169 | 170 |
171 |

172 | denotes Jon Bosak, the chair of 173 | the original XML Working Group. This name is reserved by 174 | the following decision of the W3C XML Plenary and 175 | XML Coordination groups: 176 |

177 |
178 |

179 | In appreciation for his vision, leadership and 180 | dedication the W3C XML Plenary on this 10th day of 181 | February, 2000, reserves for Jon Bosak in perpetuity 182 | the XML name "xml:Father". 183 |

184 |
185 |
186 |
187 |
188 |
189 | 190 | 191 | 192 |
193 |

About this schema document

194 | 195 |
196 |

197 | This schema defines attributes and an attribute group suitable 198 | for use by schemas wishing to allow xml:base, 199 | xml:lang, xml:space or 200 | xml:id attributes on elements they define. 201 |

202 |

203 | To enable this, such a schema must import this schema for 204 | the XML namespace, e.g. as follows: 205 |

206 |
 
207 |           <schema . . .>
208 |            . . .
209 |            <import namespace="http://www.w3.org/XML/1998/namespace"
210 |                       schemaLocation="http://www.w3.org/2001/xml.xsd"/>
211 |      
212 |

213 | or 214 |

215 |
 
216 |            <import namespace="http://www.w3.org/XML/1998/namespace"
217 |                       schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
218 |      
219 |

220 | Subsequently, qualified reference to any of the attributes or the 221 | group defined below will have the desired effect, e.g. 222 |

223 |
 
224 |           <type . . .>
225 |            . . .
226 |            <attributeGroup ref="xml:specialAttrs"/>
227 |      
228 |

229 | will define a type which will schema-validate an instance element 230 | with any of those attributes. 231 |

232 |
233 |
234 |
235 |
236 | 237 | 238 | 239 |
240 |

Versioning policy for this schema document

241 |
242 |

243 | In keeping with the XML Schema WG's standard versioning 244 | policy, this schema document will persist at 245 | 246 | http://www.w3.org/2009/01/xml.xsd. 247 |

248 |

249 | At the date of issue it can also be found at 250 | 251 | http://www.w3.org/2001/xml.xsd. 252 |

253 |

254 | The schema document at that URI may however change in the future, 255 | in order to remain compatible with the latest version of XML 256 | Schema itself, or with the XML namespace itself. In other words, 257 | if the XML Schema or XML namespaces change, the version of this 258 | document at 259 | http://www.w3.org/2001/xml.xsd 260 | 261 | will change accordingly; the version at 262 | 263 | http://www.w3.org/2009/01/xml.xsd 264 | 265 | will not change. 266 |

267 |

268 | Previous dated (and unchanging) versions of this schema 269 | document are at: 270 |

271 | 281 |
282 |
283 |
284 |
285 | 286 |
287 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/tree/element-wrapper.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree 2 | 3 | /** 4 | * ************************************************************** 5 | * 6 | * ElementWrapper 7 | * 8 | * 9 | * ************************************************************** 10 | */ 11 | 12 | import xsd.Element 13 | 14 | private[tree] case class ElementWrapper(element: Element, 15 | uniqueId: String = java.util.UUID.randomUUID.toString) { 16 | 17 | import com.github.davidmoten.xsdforms.presentation._ 18 | import com.github.davidmoten.xsdforms.presentation.Css._ 19 | import ElementWrapper._ 20 | 21 | private val e = element 22 | 23 | def hasButton = 24 | e.maxOccurs != "1" && e.minOccurs.toString != e.maxOccurs 25 | 26 | def get(key: XsdFormsAnnotation) = 27 | key.from(this) 28 | 29 | def visibility = 30 | get(Annotation.Visible) match { 31 | case Some("false") => Some(ClassInvisible) 32 | case _ => None 33 | } 34 | 35 | def isMinOccursZero = 36 | e.minOccurs.intValue == 0 && get(Annotation.Visible) != Some("false") 37 | 38 | def isTextArea = 39 | get(Annotation.Text) match { 40 | case Some(t) if (t == "textarea") => true 41 | case _ => false 42 | } 43 | 44 | def isRadio = 45 | //TODO add check is enumeration as well 46 | get(Annotation.Selector) match { 47 | case Some("radio") => true 48 | case _ => false 49 | } 50 | 51 | def isMultiple: Boolean = 52 | return (e.maxOccurs == "unbounded" || e.maxOccurs.toInt > 1) 53 | 54 | def repeats: Range = 1 to numInstances 55 | 56 | private def numInstances: Int = { 57 | 58 | val n = if (e.maxOccurs == "unbounded") 59 | NumInstancesForMultiple 60 | else 61 | e.maxOccurs.toInt 62 | 63 | get(Annotation.MaxRepeats) match { 64 | case Some(m) => Math.min(n, m.toInt) 65 | case _ => n 66 | } 67 | } 68 | 69 | private def getLabelFromName = 70 | e.name.get 71 | .replaceAll("-", " ") 72 | .replaceAll("_", " ") 73 | .split(" ") 74 | .map(s => 75 | Character.toUpperCase(s.charAt(0)) 76 | + s.substring(1, s.length)) 77 | .mkString(" ") 78 | 79 | def getLabelFromNameOrAnnotation: String = { 80 | val name = getLabelFromName 81 | get(Annotation.Label) match { 82 | case Some(x: String) => x 83 | case _ => name 84 | } 85 | } 86 | 87 | } 88 | 89 | private[tree] case class QN(namespace: String, localPart: String) 90 | 91 | private[tree] sealed trait InputType { 92 | val name: String; 93 | } 94 | private[tree] case object Checkbox extends InputType { 95 | val name = "checkbox"; 96 | } 97 | private[tree] case object TextBox extends InputType { 98 | val name = "text" 99 | } 100 | 101 | import xsd.Restriction 102 | import xsd.SimpleRestrictionModelSequence 103 | import javax.xml.namespace.QName 104 | 105 | private[tree] class MyRestriction(qName: QName) 106 | extends Restriction(None, SimpleRestrictionModelSequence(), 107 | None, Some(qName), Map()) 108 | 109 | /** 110 | * ************************************************************** 111 | * 112 | * ElementWrapper object 113 | * 114 | * 115 | * ************************************************************** 116 | */ 117 | 118 | private[tree] object ElementWrapper { 119 | 120 | import com.github.davidmoten.xsdforms.presentation._ 121 | import Css._ 122 | import xsd.Annotatedable 123 | import xsd.Restriction 124 | import xsd.NoFixedFacet 125 | import xsd.SimpleType 126 | import xsd.Pattern 127 | import xsd.ParticleOption 128 | import Util._ 129 | import XsdUtil._ 130 | import javax.xml.namespace.QName 131 | import scalaxb.DataRecord 132 | 133 | implicit def unwrap(wrapped: ElementWrapper): Element = wrapped.element 134 | 135 | val NumInstancesForMultiple = 5 136 | 137 | def valById(id: String) = "encodedValueById(\"" + id + "\")" 138 | 139 | def defaultValue(value: Option[String], r: Restriction): Option[String] = { 140 | value match { 141 | case Some(v) => { 142 | toQN(r) match { 143 | // drop the seconds off the time so js timepicker is happy 144 | case QN(xs, XsdTime.name) => Some(v.substring(0, 5)) 145 | case QN(xs, XsdDateTime.name) => Some(v.substring(0, 16)) 146 | case _ => value 147 | } 148 | } 149 | case None => value 150 | } 151 | } 152 | 153 | def isEnumeration(r: Restriction) = 154 | !getEnumeration(r).isEmpty 155 | 156 | def getEnumeration(r: Restriction): Seq[(String, NoFixedFacet)] = 157 | r.simpleRestrictionModelSequence3.facetsOption2.seq.map( 158 | _.value match { 159 | case y: NoFixedFacet => { 160 | val label = Annotation.Label.from(y) match { 161 | case Some(x) => x 162 | case None => y.valueAttribute 163 | } 164 | Some((label, y)) 165 | } 166 | case _ => None 167 | }).flatten 168 | 169 | def toQN(r: Restriction): QN = toQN(r.base.get) 170 | 171 | private def toQN(qName: QName): QN = 172 | QN(qName.getNamespaceURI(), qName.getLocalPart()) 173 | 174 | def getBasePattern(qn: QN) = { 175 | 176 | qn match { 177 | case QN(xs, XsdDecimal.name) => XsdDecimal.pattern 178 | case QN(xs, XsdInteger.name) => XsdInteger.pattern 179 | case QN(xs, XsdInt.name) => XsdInt.pattern 180 | case QN(xs, XsdLong.name) => XsdLong.pattern 181 | case QN(xs, XsdShort.name) => XsdShort.pattern 182 | case QN(xs, XsdPositiveInteger.name) => XsdPositiveInteger.pattern 183 | case QN(xs, XsdNonPositiveInteger.name) => XsdNonPositiveInteger.pattern 184 | case QN(xs, XsdNegativeInteger.name) => XsdNegativeInteger.pattern 185 | case QN(xs, XsdNonNegativeInteger.name) => XsdNonNegativeInteger.pattern 186 | case QN(xs, XsdDouble.name) => XsdDouble.pattern 187 | case QN(xs, XsdFloat.name) => XsdFloat.pattern 188 | case _ => None 189 | } 190 | } 191 | 192 | def getLabel(node: Node, typ: Option[SimpleType]) = 193 | { 194 | val e = node.element 195 | val label = e.getLabelFromNameOrAnnotation 196 | 197 | val mustOccur = e.minOccurs.intValue > 0 198 | val isText = e.typeValue match { 199 | case Some(x: QName) => x == qn("string") 200 | case _ => false 201 | } 202 | val mandatory = typ match { 203 | case None => mustOccur && !isText 204 | case Some(x) => ( 205 | x.simpleDerivationOption3.value match { 206 | case y: Restriction => 207 | (getInputType(y) match { 208 | case Checkbox => true 209 | case TextBox => isMandatory(node, y) 210 | }) 211 | case _ => 212 | !isText 213 | }) 214 | } 215 | if (mandatory) label + "*" 216 | else label 217 | } 218 | 219 | def isMandatory(node: Node, r: Restriction): Boolean = { 220 | val e = node.element 221 | val patterns = 222 | node match { 223 | case b: NodeBasic => getPatterns(b) 224 | case _ => getPatterns(r) 225 | } 226 | getInputType(r) == TextBox && 227 | e.minOccurs.intValue == 1 && 228 | ((patterns.size > 0 && 229 | !patterns.exists(java.util.regex.Pattern.matches(_, ""))) || isEnum(r)) 230 | } 231 | 232 | def isEnum(r: Restriction) = 233 | r.simpleRestrictionModelSequence3 234 | .facetsOption2 235 | .filter(x => toQName(x) == qn("enumeration")) 236 | .size > 0 237 | 238 | def restriction(node: NodeBasic): Restriction = 239 | node match { 240 | case n: NodeSimpleType => restriction(n) 241 | case n: NodeBaseType => restriction(n) 242 | } 243 | 244 | def restriction(node: NodeSimpleType): Restriction = 245 | node.typ.simpleDerivationOption3.value match { 246 | case x: Restriction => x 247 | case _ => Util.unexpected 248 | } 249 | 250 | private def restriction(node: NodeBaseType) = 251 | new MyRestriction(node.typ.qName) 252 | 253 | def getPatterns(node: NodeBasic): Seq[String] = 254 | { 255 | val r = restriction(node) 256 | 257 | val explicitPatterns = getPatterns(r) 258 | 259 | val qn = toQN(r) 260 | 261 | //calculate implicit patterns for dates, times, and datetimes 262 | val implicitPatterns = 263 | qn match { 264 | case QN(xs, XsdDate.name) => 265 | Some("\\d\\d\\d\\d-\\d\\d-\\d\\d") 266 | //TODO why spaces on end of time? 267 | case QN(xs, XsdTime.name) => 268 | Some("\\d\\d:\\d\\d *") 269 | case QN(xs, XsdDateTime.name) => 270 | Some("\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d") 271 | case _ => None 272 | } 273 | 274 | explicitPatterns ++ implicitPatterns 275 | } 276 | 277 | private def getPatterns(r: Restriction): Seq[String] = 278 | r.simpleRestrictionModelSequence3.facetsOption2.seq.flatMap(f => { 279 | f match { 280 | case DataRecord(xs, Some("pattern"), x: Pattern) => 281 | Some(x.valueAttribute) 282 | case _ => None 283 | } 284 | }) 285 | 286 | def getInputType(r: Restriction): InputType = { 287 | val qn = toQN(r) 288 | qn match { 289 | case QN(xs, XsdBoolean.name) => Checkbox 290 | case _ => TextBox 291 | } 292 | } 293 | 294 | def isCheckbox(node: NodeBasic) = 295 | Checkbox == getInputType(restriction(node)) 296 | 297 | def displayChoiceInline(choice: Choice) = 298 | "inline" == Annotation.Choice.from(choice.group).mkString 299 | 300 | def getChoiceLabel(p: ParticleOption): String = { 301 | 302 | val labels = 303 | p match { 304 | case x: Element => { 305 | Annotation.ChoiceLabel.from(x) ++ 306 | Annotation.Label.from(x) ++ 307 | Some(ElementWrapper(x).getLabelFromNameOrAnnotation) 308 | } 309 | case _ => unexpected 310 | } 311 | labels.head 312 | } 313 | 314 | def isMultiple(node: Node): Boolean = 315 | node.element.isMultiple 316 | 317 | def repeats(node: Node): Range = node.element.repeats 318 | 319 | def getExtraClasses(qn: QN) = qn match { 320 | case QN(xs, XsdDate.name) => ClassDatePicker + " " 321 | case QN(xs, XsdDateTime.name) => ClassDateTimePicker + " " 322 | case QN(xs, XsdTime.name) => ClassTimePicker + " " 323 | case _ => "" 324 | } 325 | 326 | } 327 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/main/scala/com/github/davidmoten/xsdforms/tree/traversor.scala: -------------------------------------------------------------------------------- 1 | package com.github.davidmoten.xsdforms.tree 2 | 3 | import xsd._ 4 | import javax.xml.namespace.QName 5 | import scalaxb._ 6 | 7 | /** 8 | * ************************************************************** 9 | * 10 | * SchemaTraversor 11 | * 12 | * 13 | * ************************************************************** 14 | */ 15 | 16 | private case class DataRecordWithQName[T](d: DataRecord[T]) { 17 | import XsdUtil._ 18 | def qName = toQName(d) 19 | } 20 | 21 | 22 | private[xsdforms] class SchemaTraversor(s: Schema, rootElement: Option[String], visitor: Visitor) { 23 | import Util._ 24 | import XsdUtil._ 25 | import com.github.davidmoten.xsdforms.presentation._ 26 | import com.github.davidmoten.xsdforms.Configuration 27 | private implicit def toDataRecordWithQName[T](d:DataRecord[T]) = DataRecordWithQName(d) 28 | 29 | val extensionStack = new scala.collection.mutable.Stack[ExtensionTypable] 30 | val extensionsIncludedInBaseSequence = new scala.collection.mutable.Stack[Boolean] 31 | 32 | private val topLevelElements = 33 | s.schemasequence1.flatMap(_.schemaTopOption1.value match { 34 | case y: TopLevelElement => Some(y) 35 | case _ => None 36 | }) 37 | 38 | private val topLevelComplexTypes = s 39 | .schemasequence1 40 | .flatMap(_.schemaTopOption1.value match { 41 | case y: TopLevelComplexType => Some(y) 42 | case _ => None 43 | }) 44 | 45 | private val topLevelSimpleTypes = s 46 | .schemasequence1.flatMap(_.schemaTopOption1.value match { 47 | case y: TopLevelSimpleType => Some(y) 48 | case _ => None 49 | }) 50 | 51 | private val targetNs = s.targetNamespace.getOrElse( 52 | unexpected("schema must have targetNamespace attribute")).toString 53 | 54 | private val schemaTypes = 55 | (topLevelComplexTypes.map(x => (qn(targetNs, x.name.get), x)) 56 | ++ (topLevelSimpleTypes.map(x => (qn(targetNs, x.name.get), x)))).toMap; 57 | 58 | private val baseTypes = 59 | Set(XsdDecimal, XsdString, XsdInteger, XsdDate, XsdDateTime, XsdTime, 60 | XsdBoolean, XsdInt, XsdLong, XsdShort, XsdPositiveInteger, 61 | XsdNegativeInteger, XsdNonPositiveInteger, XsdNonNegativeInteger, 62 | XsdDouble, XsdFloat) 63 | .map(qn(_)) 64 | 65 | private def getType(q: QName): AnyRef = { 66 | schemaTypes.get(q) match { 67 | case Some(x: Annotatedable) => return x 68 | case _ => 69 | if (baseTypes contains q) return BaseType(q) 70 | else unexpected("unrecognized type: " + q) 71 | } 72 | } 73 | 74 | private case class MyType(typeValue: AnyRef) 75 | 76 | /** 77 | * Visits the element definition tree. 78 | */ 79 | def traverse { 80 | topLevelAnnotations 81 | val element = 82 | if (rootElement.isDefined) 83 | topLevelElements.find( 84 | _.name match { 85 | case Some(y) => y equals rootElement.get 86 | case None => false 87 | }).getOrElse(unexpected("did not find element " + rootElement.get)) 88 | else if (topLevelElements.length == 0) 89 | unexpected("no top level elements specified in schema!") 90 | else 91 | topLevelElements(0) 92 | 93 | process(element) 94 | } 95 | 96 | private def topLevelAnnotations { 97 | //first get the children of the annotation - appinfo element 98 | val children = s.schemaoption 99 | .filter(_.qName == qn(XsdAnnotation)) 100 | .map(_.value) 101 | .map(x => x match { 102 | case y: Annotation => y 103 | case _ => unexpected 104 | }) 105 | .map(_.annotationoption) 106 | .flatten 107 | .filter(toQName(_) == QnXsdAppInfo) 108 | .map(_.value) 109 | .map(x => x match { 110 | case y: Appinfo => y 111 | case _ => unexpected 112 | }) 113 | .map(_.mixed) 114 | .flatten 115 | 116 | def extract(elementName: String):Option[String] = 117 | children 118 | .filter(_.key.isDefined) 119 | .filter(_.qName == qn(AppInfoSchema, elementName)) 120 | .map(_.value) 121 | .map(x => scala.xml.XML.loadString(x.toString)) 122 | .map(_.text).headOption 123 | 124 | val header = extract(Annotation.Header.name) 125 | val footer = extract(Annotation.Footer.name) 126 | val extraImports = extract(Annotation.ExtraImports.name) 127 | val extraScript = extract(Annotation.ExtraScript.name) 128 | val extraCss = extract(Annotation.ExtraCss.name) 129 | val configuration = Configuration(header, footer, extraImports, extraScript, extraCss) 130 | visitor.configuration(configuration) 131 | } 132 | 133 | private def process(e: Element) { 134 | e.typeValue match { 135 | case Some(x: QName) => process(e, MyType(getType(x))) 136 | case None => { 137 | e.elementoption match { 138 | case Some(x: DataRecord[ElementOption]) => { 139 | x.value match { 140 | case y: LocalComplexType => process(e, y) 141 | case y: LocalSimpleType => process(e, y) 142 | case _ => unexpected 143 | } 144 | } 145 | case _ => unexpected("unsupported " + e) 146 | } 147 | } 148 | case _ => unexpected 149 | } 150 | } 151 | 152 | private def process(e: Element, typeValue: MyType) { 153 | typeValue.typeValue match { 154 | case x: TopLevelSimpleType => process(e, x) 155 | case x: TopLevelComplexType => process(e, x) 156 | case x: BaseType => process(e, x) 157 | } 158 | } 159 | 160 | private def process(e: Element, x: SimpleType) { 161 | visitor.simpleType(e, x) 162 | } 163 | 164 | private def process(e: Element, c: ComplexType) { 165 | c.complexTypeModelOption3.value match { 166 | case x: ComplexContent => 167 | process(e, x) 168 | case x: SimpleContent => { 169 | val q = x.simplecontentoption.qName 170 | if (QnXsdExtension == q) { 171 | x.simplecontentoption.value match { 172 | case t: SimpleExtensionType => 173 | process(e, t) 174 | case _ => unexpected 175 | } 176 | } else unexpected 177 | } 178 | case x: ComplexTypeModelSequence1 => { 179 | //sequence or choice 180 | process(e, x.typeDefParticleOption1.getOrElse(unexpected)) 181 | } 182 | } 183 | } 184 | 185 | private def process(e: Element, x: DataRecord[TypeDefParticleOption]) { 186 | x.value match { 187 | case y: GroupRef => 188 | unexpected 189 | case y: ExplicitGroupable => 190 | if (x.qName == QnXsdSequence) 191 | process(e, Sequence(y)) 192 | else if (x.qName == QnXsdChoice) 193 | process(e, Choice(y)) 194 | else unexpected 195 | case _ => unexpected 196 | } 197 | } 198 | 199 | private def process(e: Element, cc: ComplexContent) { 200 | val q = cc.complexcontentoption.qName 201 | 202 | val value = cc.complexcontentoption.value 203 | if (QnXsdExtension == q) 204 | value match { 205 | case et: ExtensionType => { 206 | process(e, et) 207 | } 208 | case _ => unexpected 209 | } 210 | else unexpected 211 | } 212 | 213 | private def process(e: Element, et: ExtensionTypable) { 214 | extensionStack.push(et) 215 | process(e, MyType(getType(et.base))) 216 | } 217 | 218 | private def process(e: Element, x: BaseType) { 219 | visitor.baseType(e, x) 220 | } 221 | 222 | private def process(e: Element, x: Sequence) { 223 | val wrapWithSequence = 224 | extensionsIncludedInBaseSequence.isEmpty || !extensionsIncludedInBaseSequence.top 225 | if (wrapWithSequence) { 226 | visitor.startSequence(e) 227 | } 228 | val extensions = extensionStack.toList 229 | extensionStack.clear 230 | extensionsIncludedInBaseSequence.push(false) 231 | x.group.particleOption3.foreach(y => process(e, y.qName, y.value)) 232 | extensionsIncludedInBaseSequence.pop 233 | extensionsIncludedInBaseSequence.push(true) 234 | extensions.foreach { y => 235 | y.typeDefParticleOption3 match { 236 | case Some(t) => process(e, t) 237 | case None => {} 238 | } 239 | } 240 | extensionsIncludedInBaseSequence.pop 241 | if (wrapWithSequence) 242 | visitor.endSequence 243 | } 244 | 245 | private def process(e: Element, x: Choice) { 246 | val wrapWithSequence = !extensionStack.isEmpty 247 | val extensions = extensionStack.toList 248 | extensionStack.clear 249 | if (wrapWithSequence) { 250 | visitor.startSequence(e) 251 | } 252 | val anon = MyElement() 253 | val subElement = if (wrapWithSequence) anon else e 254 | visitor.startChoice(subElement, x) 255 | var index = 0 256 | extensionsIncludedInBaseSequence.push(false) 257 | x.group.particleOption3.foreach(y => { 258 | index = index + 1 259 | visitor.startChoiceItem(subElement, y.value, index) 260 | process(subElement, y.qName, y.value) 261 | visitor.endChoiceItem 262 | }) 263 | extensionsIncludedInBaseSequence.pop 264 | visitor.endChoice 265 | extensionsIncludedInBaseSequence.push(true) 266 | extensions.foreach { y => 267 | y.typeDefParticleOption3 match { 268 | case Some(t) => process(anon, t) 269 | case None => {} 270 | } 271 | } 272 | extensionsIncludedInBaseSequence.pop 273 | if (wrapWithSequence) 274 | visitor.endSequence 275 | } 276 | 277 | private def process(e: Element, q: QName, x: ParticleOption) { 278 | if (q == QnXsdElement) { 279 | x match { 280 | case y: LocalElementable => process(y) 281 | case _ => unexpected 282 | } 283 | } else if (q == QnXsdChoice) { 284 | x match { 285 | case y: ExplicitGroupable => process(e, Choice(y)) 286 | case _ => unexpected 287 | } 288 | } else if (q == QnXsdSequence) { 289 | x match { 290 | case y: ExplicitGroupable => process(MyElement(), Sequence(y)) 291 | case _ => unexpected 292 | } 293 | } else unexpected(q + x.toString) 294 | } 295 | } 296 | 297 | private[tree] case class MyElement(name: Option[String] = None, 298 | default: Option[String] = None, minOccurs: BigInt = BigInt(1), 299 | maxOccurs: String = "1") extends Element { 300 | val annotation: Option[xsd.Annotation] = None 301 | val elementoption: Option[scalaxb.DataRecord[xsd.ElementOption]] = None 302 | val identityConstraintOption4: Seq[scalaxb.DataRecord[xsd.IdentityConstraintOption]] = Nil 303 | val id: Option[String] = None 304 | 305 | val ref: Option[javax.xml.namespace.QName] = None 306 | val typeValue: Option[javax.xml.namespace.QName] = None 307 | val substitutionGroup: Option[javax.xml.namespace.QName] = None 308 | 309 | val fixed: Option[String] = None 310 | val nillable: Boolean = false 311 | val abstractValue: Boolean = false 312 | val finalValue: Option[String] = None 313 | val block: Option[String] = None 314 | val form: Option[xsd.FormChoice] = None 315 | val attributes: Map[String, scalaxb.DataRecord[Any]] = Map() 316 | } 317 | 318 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/test/resources/polrep.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | Marine Pollution Report (POLREP) 10 | ]]> 11 | 12 | 13 | PRIVACY STATEMENT 15 |

The Australian Maritime Safety Authority (AMSA) is collecting the information on this form to enable it to carry out its role as managing 16 | agency of the National Plan to Combat Pollution of the Sea by Oil and other Noxious and Hazardous Substances. 17 | AMSA may give some or all of this information to other government bodies, non-government organisations who have responsibilities 18 | under the National Plan, and law enforcement agencies.

19 | ]]> 20 |
21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 44 | 45 | 46 | 48 | 49 | 51 | 52 | 53 | 54 | 56 | 57 | 59 | 60 | 61 | 62 | 64 | 65 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 76 | 77 | 78 | 79 | 81 | 82 | 83 | 84 | 87 | 88 | 89 | 91 | 93 | 94 | 95 | 96 | 97 | 98 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 162 | 163 | 164 | 165 | 166 | 167 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 256 | 257 | 258 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 |
-------------------------------------------------------------------------------- /xsd-forms-generator/src/test/resources/australian-census-2011.xsd: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Australian Census 2011 extract 8 | ]]> 9 | Thanks for your time.

11 | ]]>
12 | 14 | ]]> 15 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 38 | 39 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 51 | 52 | 53 | 57 | 58 | 59 | 61 | 63 | 64 | 66 | 67 | 68 | 69 | 72 | 73 | 74 | 77 | 78 | 79 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 89 | 91 | 92 | 94 | 95 | 96 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 109 | 110 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 191 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 207 | 208 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 224 | 225 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 |
312 | -------------------------------------------------------------------------------- /xsd-forms-generator/src/docs/showcase/js/xml2json.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011-2013 Abdulla Abdurakhmanov 3 | Original sources are available at https://code.google.com/p/x2js/ 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | function X2JS(config) { 19 | 'use strict'; 20 | 21 | var VERSION = "1.1.4"; 22 | 23 | config = config || {}; 24 | initConfigDefaults(); 25 | initRequiredPolyfills(); 26 | 27 | function initConfigDefaults() { 28 | if(config.escapeMode === undefined) { 29 | config.escapeMode = true; 30 | } 31 | config.attributePrefix = config.attributePrefix || "_"; 32 | config.arrayAccessForm = config.arrayAccessForm || "none"; 33 | config.emptyNodeForm = config.emptyNodeForm || "text"; 34 | if(config.enableToStringFunc === undefined) { 35 | config.enableToStringFunc = true; 36 | } 37 | config.arrayAccessFormPaths = config.arrayAccessFormPaths || []; 38 | if(config.skipEmptyTextNodesForObj === undefined) { 39 | config.skipEmptyTextNodesForObj = true; 40 | } 41 | if(config.stripWhitespaces === undefined) { 42 | config.stripWhitespaces = true; 43 | } 44 | } 45 | 46 | function initRequiredPolyfills() { 47 | if(typeof String.prototype.trim !== 'function') { 48 | // Hello IE8- 49 | String.prototype.trim = function() { 50 | return this.replace(/^\s+|^\n+|(\s|\n)+$/g, ''); 51 | } 52 | } 53 | } 54 | 55 | var DOMNodeTypes = { 56 | ELEMENT_NODE : 1, 57 | TEXT_NODE : 3, 58 | CDATA_SECTION_NODE : 4, 59 | COMMENT_NODE : 8, 60 | DOCUMENT_NODE : 9 61 | }; 62 | 63 | function getNodeLocalName( node ) { 64 | var nodeLocalName = node.localName; 65 | if(nodeLocalName == null) // Yeah, this is IE!! 66 | nodeLocalName = node.baseName; 67 | if(nodeLocalName == null || nodeLocalName=="") // =="" is IE too 68 | nodeLocalName = node.nodeName; 69 | return nodeLocalName; 70 | } 71 | 72 | function getNodePrefix(node) { 73 | return node.prefix; 74 | } 75 | 76 | function escapeXmlChars(str) { 77 | if(typeof(str) == "string") 78 | return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/'); 79 | else 80 | return str; 81 | } 82 | 83 | function unescapeXmlChars(str) { 84 | return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(///g, '\/'); 85 | } 86 | 87 | function toArrayAccessForm(obj, childName, path) { 88 | switch(config.arrayAccessForm) { 89 | case "property": 90 | if(!(obj[childName] instanceof Array)) 91 | obj[childName+"_asArray"] = [obj[childName]]; 92 | else 93 | obj[childName+"_asArray"] = obj[childName]; 94 | break; 95 | /*case "none": 96 | break;*/ 97 | } 98 | 99 | if(!(obj[childName] instanceof Array) && config.arrayAccessFormPaths.length > 0) { 100 | var idx = 0; 101 | for(; idx < config.arrayAccessFormPaths.length; idx++) { 102 | var arrayPath = config.arrayAccessFormPaths[idx]; 103 | if( typeof arrayPath === "string" ) { 104 | if(arrayPath == path) 105 | break; 106 | } 107 | else 108 | if( arrayPath instanceof RegExp) { 109 | if(arrayPath.test(path)) 110 | break; 111 | } 112 | else 113 | if( typeof arrayPath === "function") { 114 | if(arrayPath(obj, childName, path)) 115 | break; 116 | } 117 | } 118 | if(idx!=config.arrayAccessFormPaths.length) { 119 | obj[childName] = [obj[childName]]; 120 | } 121 | } 122 | } 123 | 124 | function parseDOMChildren( node, path ) { 125 | if(node.nodeType == DOMNodeTypes.DOCUMENT_NODE) { 126 | var result = new Object; 127 | var nodeChildren = node.childNodes; 128 | // Alternative for firstElementChild which is not supported in some environments 129 | for(var cidx=0; cidx 1 && result.__text!=null && config.skipEmptyTextNodesForObj) { 211 | if( (config.stripWhitespaces && result.__text=="") || (result.__text.trim()=="")) { 212 | delete result.__text; 213 | } 214 | } 215 | delete result.__cnt; 216 | 217 | if( config.enableToStringFunc && (result.__text!=null || result.__cdata!=null )) { 218 | result.toString = function() { 219 | return (this.__text!=null? this.__text:'')+( this.__cdata!=null ? this.__cdata:''); 220 | }; 221 | } 222 | return result; 223 | } 224 | else 225 | if(node.nodeType == DOMNodeTypes.TEXT_NODE || node.nodeType == DOMNodeTypes.CDATA_SECTION_NODE) { 226 | return node.nodeValue; 227 | } 228 | } 229 | 230 | function startTag(jsonObj, element, attrList, closed) { 231 | var resultStr = "<"+ ( (jsonObj!=null && jsonObj.__prefix!=null)? (jsonObj.__prefix+":"):"") + element; 232 | if(attrList!=null) { 233 | for(var aidx = 0; aidx < attrList.length; aidx++) { 234 | var attrName = attrList[aidx]; 235 | var attrVal = jsonObj[attrName]; 236 | resultStr+=" "+attrName.substr(config.attributePrefix.length)+"='"+attrVal+"'"; 237 | } 238 | } 239 | if(!closed) 240 | resultStr+=">"; 241 | else 242 | resultStr+="/>"; 243 | return resultStr; 244 | } 245 | 246 | function endTag(jsonObj,elementName) { 247 | return ""; 248 | } 249 | 250 | function endsWith(str, suffix) { 251 | return str.indexOf(suffix, str.length - suffix.length) !== -1; 252 | } 253 | 254 | function jsonXmlSpecialElem ( jsonObj, jsonObjField ) { 255 | if((config.arrayAccessForm=="property" && endsWith(jsonObjField.toString(),("_asArray"))) 256 | || jsonObjField.toString().indexOf(config.attributePrefix)==0 257 | || jsonObjField.toString().indexOf("__")==0 258 | || (jsonObj[jsonObjField] instanceof Function) ) 259 | return true; 260 | else 261 | return false; 262 | } 263 | 264 | function jsonXmlElemCount ( jsonObj ) { 265 | var elementsCnt = 0; 266 | if(jsonObj instanceof Object ) { 267 | for( var it in jsonObj ) { 268 | if(jsonXmlSpecialElem ( jsonObj, it) ) 269 | continue; 270 | elementsCnt++; 271 | } 272 | } 273 | return elementsCnt; 274 | } 275 | 276 | function parseJSONAttributes ( jsonObj ) { 277 | var attrList = []; 278 | if(jsonObj instanceof Object ) { 279 | for( var ait in jsonObj ) { 280 | if(ait.toString().indexOf("__")== -1 && ait.toString().indexOf(config.attributePrefix)==0) { 281 | attrList.push(ait); 282 | } 283 | } 284 | } 285 | return attrList; 286 | } 287 | 288 | function parseJSONTextAttrs ( jsonTxtObj ) { 289 | var result =""; 290 | 291 | if(jsonTxtObj.__cdata!=null) { 292 | result+=""; 293 | } 294 | 295 | if(jsonTxtObj.__text!=null) { 296 | if(config.escapeMode) 297 | result+=escapeXmlChars(jsonTxtObj.__text); 298 | else 299 | result+=jsonTxtObj.__text; 300 | } 301 | return result; 302 | } 303 | 304 | function parseJSONTextObject ( jsonTxtObj ) { 305 | var result =""; 306 | 307 | if( jsonTxtObj instanceof Object ) { 308 | result+=parseJSONTextAttrs ( jsonTxtObj ); 309 | } 310 | else 311 | if(jsonTxtObj!=null) { 312 | if(config.escapeMode) 313 | result+=escapeXmlChars(jsonTxtObj); 314 | else 315 | result+=jsonTxtObj; 316 | } 317 | 318 | return result; 319 | } 320 | 321 | function parseJSONArray ( jsonArrRoot, jsonArrObj, attrList ) { 322 | var result = ""; 323 | if(jsonArrRoot.length == 0) { 324 | result+=startTag(jsonArrRoot, jsonArrObj, attrList, true); 325 | } 326 | else { 327 | for(var arIdx = 0; arIdx < jsonArrRoot.length; arIdx++) { 328 | result+=startTag(jsonArrRoot[arIdx], jsonArrObj, parseJSONAttributes(jsonArrRoot[arIdx]), false); 329 | result+=parseJSONObject(jsonArrRoot[arIdx]); 330 | result+=endTag(jsonArrRoot[arIdx],jsonArrObj); 331 | } 332 | } 333 | return result; 334 | } 335 | 336 | function parseJSONObject ( jsonObj ) { 337 | var result = ""; 338 | 339 | var elementsCnt = jsonXmlElemCount ( jsonObj ); 340 | 341 | if(elementsCnt > 0) { 342 | for( var it in jsonObj ) { 343 | 344 | if(jsonXmlSpecialElem ( jsonObj, it) ) 345 | continue; 346 | 347 | var subObj = jsonObj[it]; 348 | 349 | var attrList = parseJSONAttributes( subObj ) 350 | 351 | if(subObj == null || subObj == undefined) { 352 | result+=startTag(subObj, it, attrList, true); 353 | } 354 | else 355 | if(subObj instanceof Object) { 356 | 357 | if(subObj instanceof Array) { 358 | result+=parseJSONArray( subObj, it, attrList ); 359 | } 360 | else { 361 | var subObjElementsCnt = jsonXmlElemCount ( subObj ); 362 | if(subObjElementsCnt > 0 || subObj.__text!=null || subObj.__cdata!=null) { 363 | result+=startTag(subObj, it, attrList, false); 364 | result+=parseJSONObject(subObj); 365 | result+=endTag(subObj,it); 366 | } 367 | else { 368 | result+=startTag(subObj, it, attrList, true); 369 | } 370 | } 371 | } 372 | else { 373 | result+=startTag(subObj, it, attrList, false); 374 | result+=parseJSONTextObject(subObj); 375 | result+=endTag(subObj,it); 376 | } 377 | } 378 | } 379 | result+=parseJSONTextObject(jsonObj); 380 | 381 | return result; 382 | } 383 | 384 | this.parseXmlString = function(xmlDocStr) { 385 | if (xmlDocStr === undefined) { 386 | return null; 387 | } 388 | var xmlDoc; 389 | if (window.DOMParser) { 390 | var parser=new window.DOMParser(); 391 | xmlDoc = parser.parseFromString( xmlDocStr, "text/xml" ); 392 | } 393 | else { 394 | // IE :( 395 | if(xmlDocStr.indexOf("") + 2 ); 397 | } 398 | xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); 399 | xmlDoc.async="false"; 400 | xmlDoc.loadXML(xmlDocStr); 401 | } 402 | return xmlDoc; 403 | }; 404 | 405 | this.asArray = function(prop) { 406 | if(prop instanceof Array) 407 | return prop; 408 | else 409 | return [prop]; 410 | } 411 | 412 | this.xml2json = function (xmlDoc) { 413 | return parseDOMChildren ( xmlDoc ); 414 | }; 415 | 416 | this.xml_str2json = function (xmlDocStr) { 417 | var xmlDoc = this.parseXmlString(xmlDocStr); 418 | return this.xml2json(xmlDoc); 419 | }; 420 | 421 | this.json2xml_str = function (jsonObj) { 422 | return parseJSONObject ( jsonObj ); 423 | }; 424 | 425 | this.json2xml = function (jsonObj) { 426 | var xmlDocStr = this.json2xml_str (jsonObj); 427 | return this.parseXmlString(xmlDocStr); 428 | }; 429 | 430 | this.getVersion = function () { 431 | return VERSION; 432 | }; 433 | 434 | } 435 | --------------------------------------------------------------------------------