diff --git a/pom.xml b/pom.xml
index cd299dc..438e41d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,15 +33,15 @@
org.junit.jupiter
- junit-jupiter
+ junit-jupiter-engine
5.8.2
test
UTF-8
- 1.8
- 1.8
+ 11
+ 11
Vocabulary generator for Eclipse RDF4j and Apache Jena
@@ -50,6 +50,16 @@
src/test/resources
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M7
+
+
+ **/*Tests.java
+
+
+
org.apache.maven.plugins
maven-jar-plugin
diff --git a/src/main/java/be/belgif/vocgen/Constant.java b/src/main/java/be/belgif/vocgen/Constant.java
new file mode 100644
index 0000000..c552965
--- /dev/null
+++ b/src/main/java/be/belgif/vocgen/Constant.java
@@ -0,0 +1,27 @@
+package be.belgif.vocgen;
+
+public class Constant {
+ private String name;
+ private String label;
+
+ public Constant(String name, String label) {
+ this.name = name;
+ this.label = label;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+}
diff --git a/src/main/java/be/belgif/vocgen/Main.java b/src/main/java/be/belgif/vocgen/Main.java
index d81ea6b..478eae0 100644
--- a/src/main/java/be/belgif/vocgen/Main.java
+++ b/src/main/java/be/belgif/vocgen/Main.java
@@ -1,477 +1,494 @@
-/*
- * Copyright (c) 2017, Bart Hanssens
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-package be.belgif.vocgen;
-
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateExceptionHandler;
-
-import java.io.*;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.*;
-import java.util.function.Function;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-
-import org.eclipse.rdf4j.model.BNode;
-import org.eclipse.rdf4j.model.Literal;
-import org.eclipse.rdf4j.model.Model;
-import org.eclipse.rdf4j.model.Resource;
-import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
-import org.eclipse.rdf4j.model.vocabulary.OWL;
-import org.eclipse.rdf4j.model.vocabulary.RDF;
-import org.eclipse.rdf4j.model.vocabulary.RDFS;
-import org.eclipse.rdf4j.rio.RDFFormat;
-import org.eclipse.rdf4j.rio.Rio;
-
-import static java.util.function.Function.identity;
-
-/**
- * Quick Vocabulary class generator for Eclipse RDF4j
- *
- * @author Bart.Hanssens
- */
-public class Main {
- private Set owlClasses;
- private Set owlProperties;
- private Set owlIndivs;
-
- /**
- * Option builder
- *
- * @param c short option name
- * @param s long option name
- * @param desc description
- * @return option
- */
- private static Option opt(String c, String s, String desc) {
- return Option.builder(c).longOpt(s).required().hasArg().desc(desc).build();
- }
-
- /**
- * Command line options
- */
- private static final Options OPTS = new Options()
- .addOption(opt("f", "file", "OWL vocabulary file in TTL format"))
- .addOption(opt("d", "doc", "Documentation URL"))
- .addOption(Option.builder("a").longOpt("author").hasArg().desc( "Name of the java class author").required(false).build())
- .addOption(opt("n", "ns", "Namespace URL"))
- .addOption(opt("s", "short", "Short vocabulary name"))
- .addOption(opt("l", "long", "Long vocabulary name"))
- .addOption(opt("p", "prefix", "Namespace prefix"))
- .addOption(opt("t", "template", "one of: rdf4j, jena"))
- .addOption(Option.builder("sc").longOpt("snake-case").desc("use all caps snake case constants instead of as-is local names").required(false).build())
- .addOption(Option.builder("jp").longOpt("package").hasArg().desc( "java package").build())
- .addOption(Option.builder("o").longOpt("output-dir").required(false).hasArg().desc( "output directory").build())
- .addOption(Option.builder("c").longOpt("copyright").hasArg().required(false).desc("file containing the copyright snippet").build())
- .addOption(Option.builder("cp").longOpt("searchClasspath").hasArg(false).desc("look for input files on classpath, then in filesystem").required(false).build());
-
-
-
-
- /**
- * Get data for template from command line
- *
- * @param cmd command line
- * @return map with common data
- */
- private static Map getData(CommandLine cmd) {
- Map m = new HashMap();
- if (cmd.hasOption("a")){
- m.put("author", cmd.getOptionValue('a'));
- }
- m.put("fullname", cmd.getOptionValue('l'));
- m.put("url", cmd.getOptionValue('d'));
- m.put("nsAlias", cmd.getOptionValue('s'));
- m.put("prefix", cmd.getOptionValue('p'));
- return m;
- }
-
- /**
- * Capitalize and transform string to a valid constant for RDF4J, i.e. ALL_CAPS_SNAKE_CASE
- *
- * @param s name of the class / property
- * @return normalized string
- */
- private static String snakeCase(String s) {
- // namespace and prefix are already used in RDF4J vocabulary class
- if (s.equals("namespace") || s.equals("prefix")) {
- return s.toUpperCase() + "_PROP";
- }
- return s.replaceFirst("^_", "")
- .replaceAll("-", "_")
- .replaceAll("([a-z]+)([A-Z])", "$1_$2")
- .toUpperCase();
- }
-
- /**
- * Get local (without namespace) class names mapped to constants for RDF4J , i.e. ALL_CAPS_SNAKE_CASE
- *
- * @param m RDF Model
- * @param base namespace URI as string
- * @return map with class names and constants
- */
- private SortedMap getSnakeCaseClasses(Model m, String base) {
- SortedMap classes = new TreeMap();
- getClasses(m, base).forEach(c -> classes.put(c, snakeCase(c)));
- return classes;
- }
-
-
- /**
- * Get local (without namespace) properties mapped to constants for RDF4J, i.e. ALL_CAPS_SNAKE_CASE
- *
- * @param m RDF Model
- * @param base namespace URI as string
- * @param classes
- * @return map with properties and constants
- */
- private SortedMap getSnakeCaseProps(Model m, String base,
- Map classes) {
- SortedMap props = new TreeMap();
- // prevent duplicates when uppercasing property "name" and class "Name" to NAME
- getProps(m, base).forEach(p -> {
- String cte = snakeCase(p);
- String key = classes.containsValue(cte) ? cte + "_PROP" : cte;
- props.put(p, key);
- });
- return props;
- }
-
- /**
- * Get local (without namespace) individuals mapped to constants for RDF4J, i.e. ALL_CAPS_SNAKE_CASE.
- *
- * @param m RDF Model
- * @param base namespace URI as string
- * @return map with individuals
- */
- private Map getSnakeCaseIndivs(Model m, String base,
- Map classes, Map props) {
- Map indivs = new TreeMap();
- // prevent duplicates when uppercasing property "name" and class "Name" to NAME
- getIndivs(m, base).forEach(p -> {
- String cte = snakeCase(p);
- String key = (classes.containsValue(cte) || props.containsValue(cte)) ? cte + "_INDIV" : cte;
- indivs.put(p, key);
- });
- return indivs;
- }
-
- /**
- * Get a set of local (without namespace) class names
- *
- * @param m RDF Model
- * @param base namespace URI as string
- * @return set of local class names
- */
- private Set getClasses(Model m, String base) {
- owlClasses = m.filter(null, RDF.TYPE, OWL.CLASS).subjects();
- owlClasses.addAll(m.filter(null, RDF.TYPE, RDFS.CLASS).subjects());
-
- // discard classes outside namespace
- owlClasses.removeIf(s -> !s.toString().startsWith(base));
-
- // add subclasses
- owlClasses.addAll(owlClasses.stream()
- .flatMap(s -> m.filter(null, RDFS.SUBCLASSOF, s).subjects().stream())
- .collect(Collectors.toSet()));
-
- // discard named individuals
- owlClasses.removeAll(m.filter(null, RDF.TYPE, OWL.NAMEDINDIVIDUAL).subjects());
-
- // discard blank nodes
- owlClasses.removeIf(c -> c instanceof BNode);
-
- // discard blank nodes and return class names (without prefix)
- return owlClasses.stream()
- .map(c -> c.stringValue().replaceFirst(base, ""))
- .collect(Collectors.toSet());
- }
-
- /**
- * Get a set of local (without namespace) properties
- *
- * @param m RDF Model
- * @param base namespace URI as string
- * @return set of local property names
- */
- private Set getProps(Model m, String base) {
- owlProperties = m.filter(null, RDF.TYPE, OWL.OBJECTPROPERTY).subjects();
- owlProperties.addAll(m.filter(null, RDF.TYPE, OWL.DATATYPEPROPERTY).subjects());
- owlProperties.addAll(m.filter(null, RDF.TYPE, RDF.PROPERTY).subjects());
-
- // add subproperties
- owlProperties.addAll(owlProperties.stream()
- .flatMap(s -> m.filter(null, RDFS.SUBPROPERTYOF, s).subjects().stream())
- .collect(Collectors.toSet()));
-
- return owlProperties.stream()
- .filter(p -> p.stringValue().startsWith(base)) // only use properties from the base namespace
- .map(p -> p.stringValue().replaceFirst(base, ""))
- .collect(Collectors.toSet());
- }
-
- /**
- * Get a set of individuals (without namespace)
- *
- * @param m RDF Model
- * @param base namespace URI as string
- */
- private Set getIndivs(Model m, String base) {
- owlIndivs = m.filter(null, RDF.TYPE, OWL.NAMEDINDIVIDUAL).subjects();
- owlIndivs.addAll(m.filter(null, RDF.TYPE, OWL.INDIVIDUAL).subjects());
-
- // check for subclasses derived from other classes in this ontology
- owlIndivs.addAll(owlClasses.stream()
- .flatMap(s -> m.filter(null, RDF.TYPE, s).subjects().stream())
- .collect(Collectors.toSet()));
-
- // discard blank nodes
- owlIndivs.removeIf(c -> c instanceof BNode);
-
- // return indiv names (without prefix)
- return owlIndivs.stream()
- .filter(p -> p.stringValue().startsWith(base)) // only use individuals from the base namespace
- .map(c -> c.stringValue().replaceFirst(base, ""))
- .collect(Collectors.toSet());
- }
-
- /**
- * Get deprecated classes and properties
- *
- * @param m model
- * @param base namespace URI as string
- * @return set of deprecated classes / properties as string
- */
- private static Set getDeprecated(Model m, String base) {
- SimpleValueFactory f = SimpleValueFactory.getInstance();
- Literal tr = f.createLiteral(true);
-
- Set deprecated = m.filter(null, OWL.DEPRECATEDCLASS, tr).subjects();
- deprecated.addAll(m.filter(null, OWL.DEPRECATEDPROPERTY, tr).subjects());
- deprecated.addAll(m.filter(null, OWL.DEPRECATED, tr).subjects());
-
- return deprecated.stream()
- .map(d -> d.stringValue().replaceFirst(base, ""))
- .collect(Collectors.toSet());
- }
-
- /**
- * Read an OWL file into and RDF model
- *
- * @param file input file
- * @param base namespace URI
- * @return RDF model
- * @throws IOException
- */
- private static Model getModel(String file, String base, boolean searchForFileOnClasspath) throws IOException {
- if (searchForFileOnClasspath) {
- try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(file)) {
- if (in != null) {
- RDFFormat fmt = Rio.getParserFormatForFileName(file).orElse(RDFFormat.TURTLE);
- return Rio.parse(in, base, fmt);
- }
- }
- }
- InputStream in = new FileInputStream(file);
- RDFFormat fmt = Rio.getParserFormatForFileName(file).orElse(RDFFormat.TURTLE);
- return Rio.parse(in, base, fmt);
- }
-
- /**
- * Write output for Rdf4J or Jena
- *
- * @param cfg freemarker configuration
- * @param template project: jena or rdf4j
- * @param map template data
- * @throws IOException
- * @throws TemplateException
- */
- private static void source(Configuration cfg, TemplateType template, Map map, File outputDir) throws IOException, TemplateException {
- Template ftl = cfg.getTemplate(template.toString().toLowerCase() + ".ftl");
- String className = (String) map.get("nsAlias");
- if (!outputDir.exists()) {
- System.out.println("creating output directory " + outputDir.getAbsolutePath());
- if (!outputDir.mkdirs()) {
- throw new IOException("Unable to create output directory");
- }
- }
- File outFile = new File(outputDir, className + ".java");
- try (Writer out = new FileWriter(outFile)) {
- ftl.process(map, out);
- }
- }
-
- /**
- * Get Freemarker configuration.
- *
- * @return freemarker configuration
- */
- private static Configuration getConfig() {
- Configuration cfg = new Configuration(Configuration.VERSION_2_3_25);
- cfg.setClassLoaderForTemplateLoading(Main.class.getClassLoader(), "be/belgif/vocgen");
- cfg.setDefaultEncoding("UTF-8");
- cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
-
- return cfg;
- }
-
- /**
- * Write java class for RDF4J
- *
- * @param cfg freemarker configuration
- * @param m model
- * @param base namespace URI as string
- * @param root template data
- * @throws IOException
- * @throws TemplateException
- */
- private void writeVocab(Configuration cfg, Model m, String base, Map root, File outputDir, boolean snakeCase, TemplateType template)
- throws IOException, TemplateException {
- Map classes = snakeCase
- ? getSnakeCaseClasses(m, base)
- : getSafeNameMap(getClasses(m, base));
- Map props = snakeCase
- ? getSnakeCaseProps(m, base, classes)
- : getSafeNameMap(getProps(m, base));
- Map indivs = snakeCase
- ? getSnakeCaseIndivs(m, base, classes, props)
- : getSafeNameMap(getIndivs(m, base));
-
- root.put("classMap", classes);
- root.put("propMap", props);
- root.put("indivMap", indivs);
-
- source(cfg, template, root, outputDir);
- }
-
- private static Map getSafeNameMap(Set localNames) {
- return localNames.stream()
- .collect(Collectors.toMap(identity(), Main::toSafeJavaName));
- }
-
- private static Pattern javaLanguageKeywords = Pattern.compile(
- "(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|"
- + "break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|"
- + "instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|"
- + "void|class|finally|long|strictfp|volatile|const|float|native|super|while)"
- );
-
- private static String toSafeJavaName(String localName){
- Matcher m = javaLanguageKeywords.matcher(localName);
- if (m.matches()){
- return localName + "_";
- }
- return localName
- .replaceAll("^_", "")
- .replaceAll("[+\\-~*#&%§!]", "_");
- }
-
-
-
-
- /**
- * Main
- *
- * @param args
- * @throws java.io.IOException
- * @throws freemarker.template.TemplateException
- */
- public static void main(String[] args) throws IOException, TemplateException {
- Main main = new Main();
- try {
- main.generateVocabulary(args);
- } catch (ParseException ex) {
- System.exit(-1);
- }
-
-
- }
-
- public void generateVocabulary(String[] args) throws ParseException, IOException, TemplateException {
- CommandLine cmd;
- CommandLineParser parser = new DefaultParser();
- try {
- cmd = parser.parse(OPTS, args);
- } catch (ParseException e) {
- HelpFormatter help = new HelpFormatter();
- System.out.println(e.getMessage());
- help.printHelp("VocabGen", OPTS);
- throw e;
- }
- String ontologyFile = cmd.getOptionValue('f');
- String base = cmd.getOptionValue('n'); // namespace URI
- String javaPackage = Optional.ofNullable(cmd.getOptionValue("jp")).orElse("org.eclipse.rdf4j.model.vocabulary");
- String outputDirStr = Optional.ofNullable(cmd.getOptionValue("o")).orElse(".");
- boolean snakeCase = cmd.hasOption("sc");
- File outputDir = new File(outputDirStr);
- boolean searchFilesOnClasspath = cmd.hasOption("cp");
- String copyrightFileName = cmd.getOptionValue("c");
- String copyright = null;
- copyright = getCopyright(copyrightFileName, copyright, searchFilesOnClasspath);
- TemplateType template = TemplateType.valueOf(cmd.getOptionValue("t").toUpperCase());
- Model m = getModel(ontologyFile, base, searchFilesOnClasspath);
- Set deprecated = getDeprecated(m, base);
- // Template
- Configuration cfg = getConfig();
- Map root = getData(cmd);
- root.put("nsURL", base);
- root.put("depr", deprecated);
- root.put("package", javaPackage);
- root.put("copyright", copyright);
- writeVocab(cfg, m, base, root, outputDir, snakeCase, template);
- }
-
- private String getCopyright(String copyrightFileName, String copyright, boolean searchFilesOnClasspath) throws IOException {
- if (copyrightFileName != null){
- if (searchFilesOnClasspath) {
- try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(copyrightFileName)) {
- if (in != null) {
- return new String(in.readAllBytes(), StandardCharsets.UTF_8);
- }
- }
- }
- return Files.readString(Path.of(copyrightFileName), StandardCharsets.UTF_8);
- }
- return null;
- }
-
- private static enum TemplateType {
- RDF4J, JENA
- }
+/*
+ * Copyright (c) 2017, Bart Hanssens
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package be.belgif.vocgen;
+
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateExceptionHandler;
+import org.apache.commons.cli.*;
+import org.eclipse.rdf4j.model.*;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.model.vocabulary.OWL;
+import org.eclipse.rdf4j.model.vocabulary.RDF;
+import org.eclipse.rdf4j.model.vocabulary.RDFS;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.Rio;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.joining;
+
+/**
+ * Quick Vocabulary class generator for Eclipse RDF4j
+ *
+ * @author Bart.Hanssens
+ */
+public class Main {
+ private Set owlClasses;
+ private Set owlProperties;
+ private Set owlIndivs;
+
+ /**
+ * Option builder
+ *
+ * @param c short option name
+ * @param s long option name
+ * @param desc description
+ * @return option
+ */
+ private static Option opt(String c, String s, String desc) {
+ return Option.builder(c).longOpt(s).required().hasArg().desc(desc).build();
+ }
+
+ /**
+ * Command line options
+ */
+ private static final Options OPTS = new Options()
+ .addOption(opt("f", "file", "OWL vocabulary file in TTL format"))
+ .addOption(opt("d", "doc", "Documentation URL"))
+ .addOption(Option.builder("a").longOpt("author").hasArg().desc( "Name of the java class author").required(false).build())
+ .addOption(opt("n", "ns", "Namespace URL"))
+ .addOption(opt("s", "short", "Short vocabulary name"))
+ .addOption(opt("l", "long", "Long vocabulary name"))
+ .addOption(opt("p", "prefix", "Namespace prefix"))
+ .addOption(opt("t", "template", "one of: rdf4j, jena, plain"))
+ .addOption(Option.builder("sc").longOpt("snake-case").desc("use all caps snake case constants instead of as-is local names").required(false).build())
+ .addOption(Option.builder("jp").longOpt("package").hasArg().desc( "java package").build())
+ .addOption(Option.builder("o").longOpt("output-dir").required(false).hasArg().desc( "output directory").build())
+ .addOption(Option.builder("c").longOpt("copyright").hasArg().required(false).desc("file containing the copyright snippet").build())
+ .addOption(Option.builder("cp").longOpt("searchClasspath").hasArg(false).desc("look for input files on classpath, then in filesystem").required(false).build());
+
+
+
+
+ /**
+ * Get data for template from command line
+ *
+ * @param cmd command line
+ * @return map with common data
+ */
+ private static Map getData(CommandLine cmd) {
+ Map m = new HashMap();
+ if (cmd.hasOption("a")){
+ m.put("author", cmd.getOptionValue('a'));
+ }
+ m.put("fullname", cmd.getOptionValue('l'));
+ m.put("url", cmd.getOptionValue('d'));
+ m.put("nsAlias", cmd.getOptionValue('s'));
+ m.put("prefix", cmd.getOptionValue('p'));
+ return m;
+ }
+
+ /**
+ * Capitalize and transform string to a valid constant for RDF4J, i.e. ALL_CAPS_SNAKE_CASE
+ *
+ * @param s name of the class / property
+ * @return normalized string
+ */
+ private static String snakeCase(String s) {
+ // namespace and prefix are already used in RDF4J vocabulary class
+ if (s.equals("namespace") || s.equals("prefix")) {
+ return s.toUpperCase() + "_PROP";
+ }
+ return s.replaceFirst("^_", "")
+ .replaceAll("-", "_")
+ .replaceAll("([a-z]+)([A-Z])", "$1_$2")
+ .toUpperCase();
+ }
+
+ /**
+ * Get local (without namespace) class names mapped to constants for RDF4J , i.e. ALL_CAPS_SNAKE_CASE
+ *
+ * @param m RDF Model
+ * @param base namespace URI as string
+ * @return map with class names and constants
+ */
+ private Map getSnakeCaseClasses(Model m, String base) {
+ Map classes = new TreeMap<>();
+ getClasses(m, base).forEach(c -> classes.put(c.getName(), new Constant(snakeCase(c.getName()), c.getLabel())));
+ return classes;
+ }
+
+
+ /**
+ * Get local (without namespace) properties mapped to constants for RDF4J, i.e. ALL_CAPS_SNAKE_CASE
+ *
+ * @param m RDF Model
+ * @param base namespace URI as string
+ * @param classes
+ * @return map with properties and constants
+ */
+ private Map getSnakeCaseProps(Model m, String base,
+ Map classes) {
+ Map props = new TreeMap<>();
+ // prevent duplicates when uppercasing property "name" and class "Name" to NAME
+ getProps(m, base).forEach(p -> {
+ String cte = snakeCase(p.getName());
+ String key = classes.containsValue(cte) ? cte + "_PROP" : cte;
+ props.put(p.getName(), new Constant(key, p.getLabel()));
+ });
+ return props;
+ }
+
+ /**
+ * Get local (without namespace) individuals mapped to constants for RDF4J, i.e. ALL_CAPS_SNAKE_CASE.
+ *
+ * @param m RDF Model
+ * @param base namespace URI as string
+ * @return map with individuals
+ */
+ private Map getSnakeCaseIndivs(Model m, String base,
+ Map classes, Map props) {
+ Map indivs = new TreeMap<>();
+ // prevent duplicates when uppercasing property "name" and class "Name" to NAME
+ getIndivs(m, base).forEach(p -> {
+ String cte = snakeCase(p.getName());
+ String key = (classes.containsValue(cte) || props.containsValue(cte)) ? cte + "_INDIV" : cte;
+ indivs.put(p.getName(), new Constant(key, p.getLabel()));
+ });
+ return indivs;
+ }
+
+ /**
+ * Get a set of local (without namespace) class names
+ *
+ * @param m RDF Model
+ * @param base namespace URI as string
+ * @return set of local class names
+ */
+ private Set getClasses(Model m, String base) {
+ owlClasses = m.filter(null, RDF.TYPE, OWL.CLASS).subjects();
+ owlClasses.addAll(m.filter(null, RDF.TYPE, RDFS.CLASS).subjects());
+
+ // discard classes outside namespace
+ owlClasses.removeIf(s -> !s.toString().startsWith(base));
+
+ // add subclasses
+ owlClasses.addAll(owlClasses.stream()
+ .flatMap(s -> m.filter(null, RDFS.SUBCLASSOF, s).subjects().stream())
+ .collect(Collectors.toSet()));
+
+ // discard named individuals
+ owlClasses.removeAll(m.filter(null, RDF.TYPE, OWL.NAMEDINDIVIDUAL).subjects());
+
+ // discard blank nodes
+ owlClasses.removeIf(c -> c instanceof BNode);
+
+ // discard blank nodes and return class names (without prefix)
+ return owlClasses.stream()
+ .map(c -> new Constant(c.stringValue().replaceFirst(base, ""), getLabel(m, c)))
+ .collect(Collectors.toSet());
+ }
+
+ private String getLabel(Model m, Resource resource) {
+ Set labels =m.filter(resource, RDFS.LABEL, null).objects();
+ if (labels.isEmpty()) {
+ return null;
+ }
+ if (labels.size() == 1) {
+ return labels.stream().map(Value::stringValue).findFirst().get();
+ }
+ return labels.stream().map(Value::stringValue).collect(joining(" or "));
+ }
+
+ /**
+ * Get a set of local (without namespace) properties
+ *
+ * @param m RDF Model
+ * @param base namespace URI as string
+ * @return set of local property names
+ */
+ private Set getProps(Model m, String base) {
+ owlProperties = m.filter(null, RDF.TYPE, OWL.OBJECTPROPERTY).subjects();
+ owlProperties.addAll(m.filter(null, RDF.TYPE, OWL.DATATYPEPROPERTY).subjects());
+ owlProperties.addAll(m.filter(null, RDF.TYPE, RDF.PROPERTY).subjects());
+
+ // add subproperties
+ owlProperties.addAll(owlProperties.stream()
+ .flatMap(s -> m.filter(null, RDFS.SUBPROPERTYOF, s).subjects().stream())
+ .collect(Collectors.toSet()));
+
+ return owlProperties.stream()
+ .filter(p -> p.stringValue().startsWith(base)) // only use properties from the base namespace
+ .map(c -> new Constant(c.stringValue().replaceFirst(base, ""), getLabel(m, c)))
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Get a set of individuals (without namespace)
+ *
+ * @param m RDF Model
+ * @param base namespace URI as string
+ */
+ private Set getIndivs(Model m, String base) {
+ owlIndivs = m.filter(null, RDF.TYPE, OWL.NAMEDINDIVIDUAL).subjects();
+ owlIndivs.addAll(m.filter(null, RDF.TYPE, OWL.INDIVIDUAL).subjects());
+
+ // check for subclasses derived from other classes in this ontology
+ owlIndivs.addAll(owlClasses.stream()
+ .flatMap(s -> m.filter(null, RDF.TYPE, s).subjects().stream())
+ .collect(Collectors.toSet()));
+
+ // avoid duplication
+ owlIndivs.removeAll(owlClasses);
+ owlIndivs.removeAll(owlProperties);
+
+ // discard blank nodes
+ owlIndivs.removeIf(c -> c instanceof BNode);
+
+ // return indiv names (without prefix)
+ return owlIndivs.stream()
+ .filter(p -> p.stringValue().startsWith(base)) // only use individuals from the base namespace
+ .map(c -> new Constant(c.stringValue().replaceFirst(base, ""), getLabel(m, c)))
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Get deprecated classes and properties
+ *
+ * @param m model
+ * @param base namespace URI as string
+ * @return set of deprecated classes / properties as string
+ */
+ private static Set getDeprecated(Model m, String base) {
+ SimpleValueFactory f = SimpleValueFactory.getInstance();
+ Literal tr = f.createLiteral(true);
+
+ Set deprecated = m.filter(null, OWL.DEPRECATEDCLASS, tr).subjects();
+ deprecated.addAll(m.filter(null, OWL.DEPRECATEDPROPERTY, tr).subjects());
+ deprecated.addAll(m.filter(null, OWL.DEPRECATED, tr).subjects());
+
+ return deprecated.stream()
+ .map(d -> d.stringValue().replaceFirst(base, ""))
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Read an OWL file into and RDF model
+ *
+ * @param file input file
+ * @param base namespace URI
+ * @return RDF model
+ * @throws IOException
+ */
+ private static Model getModel(String file, String base, boolean searchForFileOnClasspath) throws IOException {
+ if (searchForFileOnClasspath) {
+ try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(file)) {
+ if (in != null) {
+ RDFFormat fmt = Rio.getParserFormatForFileName(file).orElse(RDFFormat.TURTLE);
+ return Rio.parse(in, base, fmt);
+ }
+ }
+ }
+ InputStream in = new FileInputStream(file);
+ RDFFormat fmt = Rio.getParserFormatForFileName(file).orElse(RDFFormat.TURTLE);
+ return Rio.parse(in, base, fmt);
+ }
+
+ /**
+ * Write output for Rdf4J or Jena
+ *
+ * @param cfg freemarker configuration
+ * @param template project: jena or rdf4j
+ * @param map template data
+ * @throws IOException
+ * @throws TemplateException
+ */
+ private static void source(Configuration cfg, TemplateType template, Map map, File outputDir) throws IOException, TemplateException {
+ Template ftl = cfg.getTemplate(template.toString().toLowerCase() + ".ftl");
+ String className = (String) map.get("nsAlias");
+ if (!outputDir.exists()) {
+ System.out.println("creating output directory " + outputDir.getAbsolutePath());
+ if (!outputDir.mkdirs()) {
+ throw new IOException("Unable to create output directory");
+ }
+ }
+ File outFile = new File(outputDir, className + ".java");
+ try (Writer out = new FileWriter(outFile)) {
+ ftl.process(map, out);
+ }
+ }
+
+ /**
+ * Get Freemarker configuration.
+ *
+ * @return freemarker configuration
+ */
+ private static Configuration getConfig() {
+ Configuration cfg = new Configuration(Configuration.VERSION_2_3_25);
+ cfg.setClassLoaderForTemplateLoading(Main.class.getClassLoader(), "be/belgif/vocgen");
+ cfg.setDefaultEncoding("UTF-8");
+ cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
+
+ return cfg;
+ }
+
+ /**
+ * Write java class for RDF4J
+ *
+ * @param cfg freemarker configuration
+ * @param m model
+ * @param base namespace URI as string
+ * @param root template data
+ * @throws IOException
+ * @throws TemplateException
+ */
+ private void writeVocab(Configuration cfg, Model m, String base, Map root, File outputDir, boolean snakeCase, TemplateType template)
+ throws IOException, TemplateException {
+ Map classes = snakeCase
+ ? getSnakeCaseClasses(m, base)
+ : getSafeNameMap(getClasses(m, base));
+ Map props = snakeCase
+ ? getSnakeCaseProps(m, base, classes)
+ : getSafeNameMap(getProps(m, base));
+ Map indivs = snakeCase
+ ? getSnakeCaseIndivs(m, base, classes, props)
+ : getSafeNameMap(getIndivs(m, base));
+
+ setDefaultLabelsIfMissing(classes, (String) root.get("prefix"));
+ setDefaultLabelsIfMissing(props, (String) root.get("prefix"));
+ setDefaultLabelsIfMissing(indivs, (String) root.get("prefix"));
+
+ root.put("classMap", classes);
+ root.put("propMap", props);
+ root.put("indivMap", indivs);
+
+ source(cfg, template, root, outputDir);
+ }
+
+ private void setDefaultLabelsIfMissing(Map constantMap, String nsPrefix) {
+ constantMap.values()
+ .stream()
+ .forEach(c -> {
+ if (c.getLabel() == null) {
+ c.setLabel(nsPrefix + ":" + c.getName());
+ }
+ });
+ }
+
+ private static Map getSafeNameMap(Set localNames) {
+ return new TreeMap<>(localNames.stream()
+ .collect(Collectors.toMap(c -> c.getName(), c -> new Constant(toSafeJavaName(c.getName()), c.getLabel()))));
+ }
+
+ private static Pattern javaLanguageKeywords = Pattern.compile(
+ "(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|"
+ + "break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|"
+ + "instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|"
+ + "void|class|finally|long|strictfp|volatile|const|float|native|super|while)"
+ );
+
+ private static String toSafeJavaName(String localName){
+ Matcher m = javaLanguageKeywords.matcher(localName);
+ if (m.matches()){
+ return localName + "_";
+ }
+ return localName
+ .replaceAll("^_", "")
+ .replaceAll("[+\\-~*#&%§!]", "_");
+ }
+
+
+
+
+ /**
+ * Main
+ *
+ * @param args
+ * @throws java.io.IOException
+ * @throws freemarker.template.TemplateException
+ */
+ public static void main(String[] args) throws IOException, TemplateException {
+ Main main = new Main();
+ try {
+ main.generateVocabulary(args);
+ } catch (ParseException ex) {
+ System.exit(-1);
+ }
+
+
+ }
+
+ public void generateVocabulary(String[] args) throws ParseException, IOException, TemplateException {
+ CommandLine cmd;
+ CommandLineParser parser = new DefaultParser();
+ try {
+ cmd = parser.parse(OPTS, args);
+ } catch (ParseException e) {
+ HelpFormatter help = new HelpFormatter();
+ System.out.println(e.getMessage());
+ help.printHelp("VocabGen", OPTS);
+ throw e;
+ }
+ String ontologyFile = cmd.getOptionValue('f');
+ String base = cmd.getOptionValue('n'); // namespace URI
+ String javaPackage = Optional.ofNullable(cmd.getOptionValue("jp")).orElse("org.eclipse.rdf4j.model.vocabulary");
+ String outputDirStr = Optional.ofNullable(cmd.getOptionValue("o")).orElse(".");
+ boolean snakeCase = cmd.hasOption("sc");
+ File outputDir = new File(outputDirStr);
+ boolean searchFilesOnClasspath = cmd.hasOption("cp");
+ String copyrightFileName = cmd.getOptionValue("c");
+ String copyright = null;
+ copyright = getCopyright(copyrightFileName, copyright, searchFilesOnClasspath);
+ TemplateType template = TemplateType.valueOf(cmd.getOptionValue("t").toUpperCase());
+ Model m = getModel(ontologyFile, base, searchFilesOnClasspath);
+ Set deprecated = getDeprecated(m, base);
+ // Template
+ Configuration cfg = getConfig();
+ Map root = getData(cmd);
+ root.put("nsURL", base);
+ root.put("depr", deprecated);
+ root.put("package", javaPackage);
+ root.put("copyright", copyright);
+ writeVocab(cfg, m, base, root, outputDir, snakeCase, template);
+ }
+
+ private String getCopyright(String copyrightFileName, String copyright, boolean searchFilesOnClasspath) throws IOException {
+ if (copyrightFileName != null){
+ if (searchFilesOnClasspath) {
+ try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(copyrightFileName)) {
+ if (in != null) {
+ return new String(in.readAllBytes(), StandardCharsets.UTF_8);
+ }
+ }
+ }
+ return Files.readString(Path.of(copyrightFileName), StandardCharsets.UTF_8);
+ }
+ return null;
+ }
+
+ private static enum TemplateType {
+ RDF4J, JENA, PLAIN
+ }
}
\ No newline at end of file
diff --git a/src/main/resources/be/belgif/vocgen/jena.ftl b/src/main/resources/be/belgif/vocgen/jena.ftl
index 79b00d8..8f1515a 100644
--- a/src/main/resources/be/belgif/vocgen/jena.ftl
+++ b/src/main/resources/be/belgif/vocgen/jena.ftl
@@ -33,25 +33,34 @@ public class ${nsAlias} {
// Classes
<#list classMap as class, const>
+ <#if const.label??>
+ /** ${const.label}
**/
+ #if>
<#if depr?seq_contains(class)>
@Deprecated
#if>
- public static final Resource ${const} = m.createResource(NS + "${class}");
+ public static final Resource ${const.name} = m.createResource(NS + "${class}");
#list>
// Properties
<#list propMap as prop, const>
+ <#if const.label??>
+ /** ${const.label}
**/
+ #if>
<#if depr?seq_contains(prop)>
@Deprecated
#if>
- public static final Property ${const} = m.createProperty(NS + "${prop}");
+ public static final Property ${const.name} = m.createProperty(NS + "${prop}");
#list>
// Individuals
<#list indivMap as ind, const>
+ <#if const.label??>
+ /** ${const.label}
**/
+ #if>
<#if depr?seq_contains(ind)>
@Deprecated
#if>
- public static final Individual ${ind} = m.createProperty(NS + "${ind}");
+ public static final Individual ${const.name} = m.createProperty(NS + "${ind}");
#list>
}
diff --git a/src/main/resources/be/belgif/vocgen/plain.ftl b/src/main/resources/be/belgif/vocgen/plain.ftl
new file mode 100644
index 0000000..51c81bd
--- /dev/null
+++ b/src/main/resources/be/belgif/vocgen/plain.ftl
@@ -0,0 +1,58 @@
+<#if copyright??>
+ ${copyright}
+#if>
+package ${package};
+
+/**
+ * Constants for the ${fullname}.
+ *
+ * @see ${fullname}
+ */
+public class ${nsAlias} {
+
+ /**
+ * The ${nsAlias} namespace: ${nsURL}
+ */
+ public static final String NS = "${nsURL}";
+
+ /**
+ * Returns the URI for this schema
+ * @return URI
+ */
+ public static String getURI() {
+ return NS;
+ }
+
+ // Classes
+ <#list classMap as class, const>
+ <#if const.label??>
+ /** ${const.label}
**/
+ #if>
+ <#if depr?seq_contains(class)>
+ @Deprecated
+ #if>
+ public static final String ${const.name} = NS + "${class}";
+ #list>
+
+ // Properties
+ <#list propMap as prop, const>
+ <#if const.label??>
+ /** ${const.label}
**/
+ #if>
+ <#if depr?seq_contains(prop)>
+ @Deprecated
+ #if>
+ public static final String ${const.name} = NS + "${prop}";
+ #list>
+
+ // Individuals
+ <#list indivMap as ind, const>
+ <#if const.label??>
+ /** ${const.label}
**/
+ #if>
+ <#if depr?seq_contains(ind)>
+ @Deprecated
+ #if>
+ public static final String ${const.name} = NS + "${ind}";
+ #list>
+}
diff --git a/src/main/resources/be/belgif/vocgen/rdf4j.ftl b/src/main/resources/be/belgif/vocgen/rdf4j.ftl
index 8679af9..be08ee1 100644
--- a/src/main/resources/be/belgif/vocgen/rdf4j.ftl
+++ b/src/main/resources/be/belgif/vocgen/rdf4j.ftl
@@ -35,31 +35,37 @@ public class ${nsAlias} {
// Classes
<#list classMap as class, const>
- /** ${prefix}:${class} */
+ <#if const.label??>
+ /** ${const.label}
**/
+ #if>
<#if depr?seq_contains(class)>
@Deprecated
#if>
- public static final IRI ${const} = create("${class}");
+ public static final IRI ${const.name} = create("${class}");
#list>
// Properties
<#list propMap as prop, const>
- /** ${prefix}:${prop} */
+ <#if const.label??>
+ /** ${const.label}
**/
+ #if>
<#if depr?seq_contains(prop)>
@Deprecated
#if>
- public static final IRI ${const} = create("${prop}");
+ public static final IRI ${const.name} = create("${prop}");
#list>
// Individuals
<#list indivMap as indiv, const>
- /** ${prefix}:${indiv} */
+ <#if const.label??>
+ /** ${const.label}
**/
+ #if>
<#if depr?seq_contains(indiv)>
@Deprecated
#if>
- public static final IRI ${const} = create("${indiv}");
+ public static final IRI ${const.name} = create("${indiv}");
#list>
diff --git a/src/test/java/be/belgif/vocgen/VocGenTests.java b/src/test/java/be/belgif/vocgen/VocGenTests.java
index dfde593..4dfb985 100644
--- a/src/test/java/be/belgif/vocgen/VocGenTests.java
+++ b/src/test/java/be/belgif/vocgen/VocGenTests.java
@@ -6,8 +6,7 @@
import org.apache.commons.cli.ParseException;
import org.junit.jupiter.api.Test;
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -17,8 +16,26 @@ public class VocGenTests {
Main main = new Main();
@Test
- public void testNoArgs() {
- assertThrows(MissingOptionException.class, () -> main.generateVocabulary(new String[] {}));
+ public void testNoArgs() throws IOException {
+ String testName = "testNoArgs";
+ String filename = "System.out";
+ Path outputFilePath = getOutputFilePath(testName, filename);
+ File outputFile = outputFilePath.toFile();
+ File dir = outputFile.getParentFile();
+ if (!dir.exists()) {
+ if (!dir.mkdirs()) {
+ fail("could not create output directory " + dir.getAbsolutePath());
+ }
+ }
+ PrintStream outContent = new PrintStream(outputFile);
+ PrintStream originalSystemOut = System.out;
+ System.setOut(new PrintStream(outContent));
+ try {
+ assertThrows(MissingOptionException.class, () -> main.generateVocabulary(new String[] {}));
+ assertFileEqualsExpected(testName, filename);
+ } finally {
+ System.setOut(originalSystemOut);
+ }
}
@Test
@@ -57,6 +74,24 @@ public void testBasic_Jena() throws TemplateException, ParseException, IOExcepti
assertFileEqualsExpected(testName, "RDF.java");
}
+ @Test
+ public void testBasic_Plain() throws TemplateException, ParseException, IOException {
+ String testName = "testBasic_Plain";
+ main.generateVocabulary(new String[] {
+ "--file", "src/test/resources/rdf.ttl",
+ "--template", "plain",
+ "--long", "The RDF vocabulary",
+ "--short", "RDF",
+ "--ns", "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
+ "--prefix", "rdf",
+ "--doc", "https://www.w3.org/TR/2014/REC-rdf11-concepts-20140225/",
+ "--author", "The Author",
+ "--package", "org.w3.vocab",
+ "--output-dir", testOutputDir(testName),
+ });
+ assertFileEqualsExpected(testName, "RDF.java");
+ }
+
@Test
public void testBasic_SearchClasspath() throws TemplateException, ParseException, IOException {
String testName = "testBasic_SearchClasspath";
@@ -115,33 +150,60 @@ public void testBasic_Copyright_SearchClasspath() throws TemplateException, Pars
assertFileEqualsExpected(testName, "RDF.java");
}
+ @Test
+ public void testBasic_NoLabels() throws TemplateException, ParseException, IOException {
+ String testName = "testBasic_NoLabels";
+ main.generateVocabulary(new String[] {
+ "--searchClasspath",
+ "--file", "src/test/resources/rdf-nolabels.ttl",
+ "--template", "rdf4j",
+ "--long", "The RDF vocabulary",
+ "--short", "RDF",
+ "--ns", "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
+ "--prefix", "rdf",
+ "--doc", "https://www.w3.org/TR/2014/REC-rdf11-concepts-20140225/",
+ "--author", "The Author",
+ "--package", "org.w3.vocab",
+ "--output-dir", testOutputDir(testName),
+ });
+ assertFileEqualsExpected(testName, "RDF.java");
+ }
private String testOutputDir(String testName) {
return "target/test-output/" + testName;
}
private void assertFileEqualsExpected(String directory, String filename) throws IOException {
- Path outputFilePath = Path.of("target/test-output/" + directory + "/" + filename);
- Path expectedFilePath = Path.of("src/test/resources/expected/" + directory + "/" + filename);
- File outputFile = outputFilePath.toFile();
+ Path expectedFilePath = getExpectedFilePath(directory, filename);
File expectedFile = expectedFilePath.toFile();
- assertTrue(outputFile::exists, "output file " + outputFile.getAbsolutePath() + " does not exist");
assertTrue(expectedFile::exists, "expected file " + expectedFile.getAbsolutePath() + " does not exist");
+ String expectedFileContent = Files.readString(expectedFilePath, Charsets.UTF_8);
+ Path outputFilePath = getOutputFilePath(directory, filename);
+ File outputFile = outputFilePath.toFile();
+ assertTrue(outputFile::exists, "output file " + outputFile.getAbsolutePath() + " does not exist");
+ String actualFileContent = Files.readString(outputFilePath, Charsets.UTF_8);
assertEquals(
- format(Files.readString(expectedFilePath, Charsets.UTF_8)),
- format(Files.readString(outputFilePath, Charsets.UTF_8)),
+ format(expectedFileContent),
+ format(actualFileContent),
"Output file " + outputFile.getAbsolutePath() + " content differs from expected content in "
+ expectedFile.getAbsolutePath());
}
+ private Path getOutputFilePath(String directory, String filename) {
+ return Path.of("target/test-output/" + directory + "/" + filename);
+ }
+ private Path getExpectedFilePath(String directory, String filename) {
+ return Path.of("src/test/resources/expected/" + directory + "/" + filename);
+ }
/**
* Remove any IDE formatting we might have introduced by managing the expected file in the IDE.
+ *
* @param input the generated file's content.
* @return the content, hopefully formatted in such a way that comparing output and expected output shows only interesting differences.
*/
- private String format(String input){
+ private String format(String input) {
return input.replaceAll("[\\s]+\n", "\n").replaceAll("\n[\\s\\t]+(\\S)", "\n $1");
}
}
diff --git a/src/test/resources/expected/testBasic/RDF.java b/src/test/resources/expected/testBasic/RDF.java
index c6c49d6..27923cc 100644
--- a/src/test/resources/expected/testBasic/RDF.java
+++ b/src/test/resources/expected/testBasic/RDF.java
@@ -31,87 +31,60 @@ public class RDF {
public static final Namespace NS = new SimpleNamespace(PREFIX, NAMESPACE);
// Classes
- /** rdf:Statement */
- public static final IRI Statement = create("Statement");
-
- /** rdf:Alt */
+ /** Alt
**/
public static final IRI Alt = create("Alt");
- /** rdf:Bag */
+ /** Bag
**/
public static final IRI Bag = create("Bag");
- /** rdf:List */
+ /** CompoundLiteral
**/
+ public static final IRI CompoundLiteral = create("CompoundLiteral");
+
+ /** List
**/
public static final IRI List = create("List");
- /** rdf:Property */
+ /** Property
**/
public static final IRI Property = create("Property");
- /** rdf:CompoundLiteral */
- public static final IRI CompoundLiteral = create("CompoundLiteral");
-
- /** rdf:Seq */
+ /** Seq
**/
public static final IRI Seq = create("Seq");
+ /** Statement
**/
+ public static final IRI Statement = create("Statement");
- // Properties
- /** rdf:predicate */
- public static final IRI predicate = create("predicate");
- /** rdf:rest */
- public static final IRI rest = create("rest");
+ // Properties
+ /** direction
**/
+ public static final IRI direction = create("direction");
- /** rdf:subject */
- public static final IRI subject = create("subject");
+ /** first
**/
+ public static final IRI first = create("first");
- /** rdf:language */
+ /** language
**/
public static final IRI language = create("language");
- /** rdf:type */
- public static final IRI type = create("type");
-
- /** rdf:value */
- public static final IRI value = create("value");
-
- /** rdf:first */
- public static final IRI first = create("first");
-
- /** rdf:object */
+ /** object
**/
public static final IRI object = create("object");
- /** rdf:direction */
- public static final IRI direction = create("direction");
-
-
- // Individuals
- /** rdf:nil */
- public static final IRI nil = create("nil");
+ /** predicate
**/
+ public static final IRI predicate = create("predicate");
- /** rdf:rest */
+ /** rest
**/
public static final IRI rest = create("rest");
- /** rdf:predicate */
- public static final IRI predicate = create("predicate");
-
- /** rdf:subject */
+ /** subject
**/
public static final IRI subject = create("subject");
- /** rdf:language */
- public static final IRI language = create("language");
-
- /** rdf:type */
+ /** type
**/
public static final IRI type = create("type");
- /** rdf:value */
+ /** value
**/
public static final IRI value = create("value");
- /** rdf:first */
- public static final IRI first = create("first");
- /** rdf:object */
- public static final IRI object = create("object");
-
- /** rdf:direction */
- public static final IRI direction = create("direction");
+ // Individuals
+ /** nil
**/
+ public static final IRI nil = create("nil");
private static IRI create(String localName) {
diff --git a/src/test/resources/expected/testBasic_Copyright/RDF.java b/src/test/resources/expected/testBasic_Copyright/RDF.java
index f1cd399..1e17a3f 100644
--- a/src/test/resources/expected/testBasic_Copyright/RDF.java
+++ b/src/test/resources/expected/testBasic_Copyright/RDF.java
@@ -38,87 +38,60 @@ public class RDF {
public static final Namespace NS = new SimpleNamespace(PREFIX, NAMESPACE);
// Classes
- /** rdf:Statement */
- public static final IRI Statement = create("Statement");
-
- /** rdf:Alt */
+ /** Alt
**/
public static final IRI Alt = create("Alt");
- /** rdf:Bag */
+ /** Bag
**/
public static final IRI Bag = create("Bag");
- /** rdf:List */
+ /** CompoundLiteral
**/
+ public static final IRI CompoundLiteral = create("CompoundLiteral");
+
+ /** List
**/
public static final IRI List = create("List");
- /** rdf:Property */
+ /** Property
**/
public static final IRI Property = create("Property");
- /** rdf:CompoundLiteral */
- public static final IRI CompoundLiteral = create("CompoundLiteral");
-
- /** rdf:Seq */
+ /** Seq
**/
public static final IRI Seq = create("Seq");
+ /** Statement
**/
+ public static final IRI Statement = create("Statement");
- // Properties
- /** rdf:predicate */
- public static final IRI predicate = create("predicate");
- /** rdf:rest */
- public static final IRI rest = create("rest");
+ // Properties
+ /** direction
**/
+ public static final IRI direction = create("direction");
- /** rdf:subject */
- public static final IRI subject = create("subject");
+ /** first
**/
+ public static final IRI first = create("first");
- /** rdf:language */
+ /** language
**/
public static final IRI language = create("language");
- /** rdf:type */
- public static final IRI type = create("type");
-
- /** rdf:value */
- public static final IRI value = create("value");
-
- /** rdf:first */
- public static final IRI first = create("first");
-
- /** rdf:object */
+ /** object
**/
public static final IRI object = create("object");
- /** rdf:direction */
- public static final IRI direction = create("direction");
-
-
- // Individuals
- /** rdf:nil */
- public static final IRI nil = create("nil");
+ /** predicate
**/
+ public static final IRI predicate = create("predicate");
- /** rdf:rest */
+ /** rest
**/
public static final IRI rest = create("rest");
- /** rdf:predicate */
- public static final IRI predicate = create("predicate");
-
- /** rdf:subject */
+ /** subject
**/
public static final IRI subject = create("subject");
- /** rdf:language */
- public static final IRI language = create("language");
-
- /** rdf:type */
+ /** type
**/
public static final IRI type = create("type");
- /** rdf:value */
+ /** value
**/
public static final IRI value = create("value");
- /** rdf:first */
- public static final IRI first = create("first");
- /** rdf:object */
- public static final IRI object = create("object");
-
- /** rdf:direction */
- public static final IRI direction = create("direction");
+ // Individuals
+ /** nil
**/
+ public static final IRI nil = create("nil");
private static IRI create(String localName) {
diff --git a/src/test/resources/expected/testBasic_Copyright_SearchClasspath/RDF.java b/src/test/resources/expected/testBasic_Copyright_SearchClasspath/RDF.java
index f1cd399..1e17a3f 100644
--- a/src/test/resources/expected/testBasic_Copyright_SearchClasspath/RDF.java
+++ b/src/test/resources/expected/testBasic_Copyright_SearchClasspath/RDF.java
@@ -38,87 +38,60 @@ public class RDF {
public static final Namespace NS = new SimpleNamespace(PREFIX, NAMESPACE);
// Classes
- /** rdf:Statement */
- public static final IRI Statement = create("Statement");
-
- /** rdf:Alt */
+ /** Alt
**/
public static final IRI Alt = create("Alt");
- /** rdf:Bag */
+ /** Bag
**/
public static final IRI Bag = create("Bag");
- /** rdf:List */
+ /** CompoundLiteral
**/
+ public static final IRI CompoundLiteral = create("CompoundLiteral");
+
+ /** List
**/
public static final IRI List = create("List");
- /** rdf:Property */
+ /** Property
**/
public static final IRI Property = create("Property");
- /** rdf:CompoundLiteral */
- public static final IRI CompoundLiteral = create("CompoundLiteral");
-
- /** rdf:Seq */
+ /** Seq
**/
public static final IRI Seq = create("Seq");
+ /** Statement
**/
+ public static final IRI Statement = create("Statement");
- // Properties
- /** rdf:predicate */
- public static final IRI predicate = create("predicate");
- /** rdf:rest */
- public static final IRI rest = create("rest");
+ // Properties
+ /** direction
**/
+ public static final IRI direction = create("direction");
- /** rdf:subject */
- public static final IRI subject = create("subject");
+ /** first
**/
+ public static final IRI first = create("first");
- /** rdf:language */
+ /** language
**/
public static final IRI language = create("language");
- /** rdf:type */
- public static final IRI type = create("type");
-
- /** rdf:value */
- public static final IRI value = create("value");
-
- /** rdf:first */
- public static final IRI first = create("first");
-
- /** rdf:object */
+ /** object
**/
public static final IRI object = create("object");
- /** rdf:direction */
- public static final IRI direction = create("direction");
-
-
- // Individuals
- /** rdf:nil */
- public static final IRI nil = create("nil");
+ /** predicate
**/
+ public static final IRI predicate = create("predicate");
- /** rdf:rest */
+ /** rest
**/
public static final IRI rest = create("rest");
- /** rdf:predicate */
- public static final IRI predicate = create("predicate");
-
- /** rdf:subject */
+ /** subject
**/
public static final IRI subject = create("subject");
- /** rdf:language */
- public static final IRI language = create("language");
-
- /** rdf:type */
+ /** type
**/
public static final IRI type = create("type");
- /** rdf:value */
+ /** value
**/
public static final IRI value = create("value");
- /** rdf:first */
- public static final IRI first = create("first");
- /** rdf:object */
- public static final IRI object = create("object");
-
- /** rdf:direction */
- public static final IRI direction = create("direction");
+ // Individuals
+ /** nil
**/
+ public static final IRI nil = create("nil");
private static IRI create(String localName) {
diff --git a/src/test/resources/expected/testBasic_Jena/RDF.java b/src/test/resources/expected/testBasic_Jena/RDF.java
index 503a8e6..7800a7f 100644
--- a/src/test/resources/expected/testBasic_Jena/RDF.java
+++ b/src/test/resources/expected/testBasic_Jena/RDF.java
@@ -1,4 +1,4 @@
-package org.apache.jena.vocabulary;
+package org.w3.vocab;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
@@ -29,34 +29,42 @@ public static String getURI() {
}
// Classes
- public static final Resource Statement = m.createResource(NS + "Statement");
+ /** Alt
**/
public static final Resource Alt = m.createResource(NS + "Alt");
+ /** Bag
**/
public static final Resource Bag = m.createResource(NS + "Bag");
+ /** CompoundLiteral
**/
+ public static final Resource CompoundLiteral = m.createResource(NS + "CompoundLiteral");
+ /** List
**/
public static final Resource List = m.createResource(NS + "List");
+ /** Property
**/
public static final Resource Property = m.createResource(NS + "Property");
- public static final Resource CompoundLiteral = m.createResource(NS + "CompoundLiteral");
+ /** Seq
**/
public static final Resource Seq = m.createResource(NS + "Seq");
+ /** Statement
**/
+ public static final Resource Statement = m.createResource(NS + "Statement");
// Properties
+ /** direction
**/
+ public static final Property direction = m.createProperty(NS + "direction");
+ /** first
**/
+ public static final Property first = m.createProperty(NS + "first");
+ /** language
**/
+ public static final Property language = m.createProperty(NS + "language");
+ /** object
**/
+ public static final Property object = m.createProperty(NS + "object");
+ /** predicate
**/
public static final Property predicate = m.createProperty(NS + "predicate");
+ /** rest
**/
public static final Property rest = m.createProperty(NS + "rest");
+ /** subject
**/
public static final Property subject = m.createProperty(NS + "subject");
- public static final Property language = m.createProperty(NS + "language");
+ /** type
**/
public static final Property type = m.createProperty(NS + "type");
+ /** value
**/
public static final Property value = m.createProperty(NS + "value");
- public static final Property first = m.createProperty(NS + "first");
- public static final Property object = m.createProperty(NS + "object");
- public static final Property direction = m.createProperty(NS + "direction");
// Individuals
+ /** nil
**/
public static final Individual nil = m.createProperty(NS + "nil");
- public static final Individual rest = m.createProperty(NS + "rest");
- public static final Individual predicate = m.createProperty(NS + "predicate");
- public static final Individual subject = m.createProperty(NS + "subject");
- public static final Individual language = m.createProperty(NS + "language");
- public static final Individual type = m.createProperty(NS + "type");
- public static final Individual value = m.createProperty(NS + "value");
- public static final Individual first = m.createProperty(NS + "first");
- public static final Individual object = m.createProperty(NS + "object");
- public static final Individual direction = m.createProperty(NS + "direction");
}
diff --git a/src/test/resources/expected/testBasic_NoLabels/RDF.java b/src/test/resources/expected/testBasic_NoLabels/RDF.java
new file mode 100644
index 0000000..c70a109
--- /dev/null
+++ b/src/test/resources/expected/testBasic_NoLabels/RDF.java
@@ -0,0 +1,94 @@
+package org.w3.vocab;
+
+import org.eclipse.rdf4j.model.IRI;
+import org.eclipse.rdf4j.model.Namespace;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.SimpleNamespace;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+
+
+/**
+ * Constants for the The RDF vocabulary.
+ *
+ * @see The RDF vocabulary
+ *
+ * @author The Author
+ */
+public class RDF {
+ /**
+ * The RDF namespace: http://www.w3.org/1999/02/22-rdf-syntax-ns#
+ */
+ public static final String NAMESPACE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+
+ /**
+ * Recommended prefix for the namespace: "rdf"
+ */
+ public static final String PREFIX = "rdf";
+
+ /**
+ * An immutable {@link Namespace} constant that represents the namespace.
+ */
+ public static final Namespace NS = new SimpleNamespace(PREFIX, NAMESPACE);
+
+ // Classes
+ /** rdf:Alt
**/
+ public static final IRI Alt = create("Alt");
+
+ /** rdf:Bag
**/
+ public static final IRI Bag = create("Bag");
+
+ /** rdf:CompoundLiteral
**/
+ public static final IRI CompoundLiteral = create("CompoundLiteral");
+
+ /** rdf:List
**/
+ public static final IRI List = create("List");
+
+ /** rdf:Property
**/
+ public static final IRI Property = create("Property");
+
+ /** rdf:Seq
**/
+ public static final IRI Seq = create("Seq");
+
+ /** rdf:Statement
**/
+ public static final IRI Statement = create("Statement");
+
+
+ // Properties
+ /** rdf:direction
**/
+ public static final IRI direction = create("direction");
+
+ /** rdf:first
**/
+ public static final IRI first = create("first");
+
+ /** rdf:language
**/
+ public static final IRI language = create("language");
+
+ /** rdf:object
**/
+ public static final IRI object = create("object");
+
+ /** rdf:predicate
**/
+ public static final IRI predicate = create("predicate");
+
+ /** rdf:rest
**/
+ public static final IRI rest = create("rest");
+
+ /** rdf:subject
**/
+ public static final IRI subject = create("subject");
+
+ /** rdf:type
**/
+ public static final IRI type = create("type");
+
+ /** rdf:value
**/
+ public static final IRI value = create("value");
+
+
+ // Individuals
+ /** rdf:nil
**/
+ public static final IRI nil = create("nil");
+
+
+ private static IRI create(String localName) {
+ return SimpleValueFactory.getInstance().createIRI(RDF.NAMESPACE, localName);
+ }
+}
+
diff --git a/src/test/resources/expected/testBasic_Plain/RDF.java b/src/test/resources/expected/testBasic_Plain/RDF.java
new file mode 100644
index 0000000..d0062fe
--- /dev/null
+++ b/src/test/resources/expected/testBasic_Plain/RDF.java
@@ -0,0 +1,62 @@
+package org.w3.vocab;
+
+/**
+ * Constants for the The RDF vocabulary.
+ *
+ * @see The RDF vocabulary
+ */
+public class RDF {
+
+ /**
+ * The RDF namespace: http://www.w3.org/1999/02/22-rdf-syntax-ns#
+ */
+ public static final String NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+
+ /**
+ * Returns the URI for this schema
+ * @return URI
+ */
+ public static String getURI() {
+ return NS;
+ }
+
+ // Classes
+ /** Alt
**/
+ public static final String Alt = NS + "Alt";
+ /** Bag
**/
+ public static final String Bag = NS + "Bag";
+ /** CompoundLiteral
**/
+ public static final String CompoundLiteral = NS + "CompoundLiteral";
+ /** List
**/
+ public static final String List = NS + "List";
+ /** Property
**/
+ public static final String Property = NS + "Property";
+ /** Seq
**/
+ public static final String Seq = NS + "Seq";
+ /** Statement
**/
+ public static final String Statement = NS + "Statement";
+
+ // Properties
+ /** direction
**/
+ public static final String direction = NS + "direction";
+ /** first
**/
+ public static final String first = NS + "first";
+ /** language
**/
+ public static final String language = NS + "language";
+ /** object
**/
+ public static final String object = NS + "object";
+ /** predicate
**/
+ public static final String predicate = NS + "predicate";
+ /** rest
**/
+ public static final String rest = NS + "rest";
+ /** subject
**/
+ public static final String subject = NS + "subject";
+ /** type
**/
+ public static final String type = NS + "type";
+ /** value
**/
+ public static final String value = NS + "value";
+
+ // Individuals
+ /** nil
**/
+ public static final String nil = NS + "nil";
+}
diff --git a/src/test/resources/expected/testBasic_SearchClasspath/RDF.java b/src/test/resources/expected/testBasic_SearchClasspath/RDF.java
index c6c49d6..27923cc 100644
--- a/src/test/resources/expected/testBasic_SearchClasspath/RDF.java
+++ b/src/test/resources/expected/testBasic_SearchClasspath/RDF.java
@@ -31,87 +31,60 @@ public class RDF {
public static final Namespace NS = new SimpleNamespace(PREFIX, NAMESPACE);
// Classes
- /** rdf:Statement */
- public static final IRI Statement = create("Statement");
-
- /** rdf:Alt */
+ /** Alt
**/
public static final IRI Alt = create("Alt");
- /** rdf:Bag */
+ /** Bag
**/
public static final IRI Bag = create("Bag");
- /** rdf:List */
+ /** CompoundLiteral
**/
+ public static final IRI CompoundLiteral = create("CompoundLiteral");
+
+ /** List
**/
public static final IRI List = create("List");
- /** rdf:Property */
+ /** Property
**/
public static final IRI Property = create("Property");
- /** rdf:CompoundLiteral */
- public static final IRI CompoundLiteral = create("CompoundLiteral");
-
- /** rdf:Seq */
+ /** Seq
**/
public static final IRI Seq = create("Seq");
+ /** Statement
**/
+ public static final IRI Statement = create("Statement");
- // Properties
- /** rdf:predicate */
- public static final IRI predicate = create("predicate");
- /** rdf:rest */
- public static final IRI rest = create("rest");
+ // Properties
+ /** direction
**/
+ public static final IRI direction = create("direction");
- /** rdf:subject */
- public static final IRI subject = create("subject");
+ /** first
**/
+ public static final IRI first = create("first");
- /** rdf:language */
+ /** language
**/
public static final IRI language = create("language");
- /** rdf:type */
- public static final IRI type = create("type");
-
- /** rdf:value */
- public static final IRI value = create("value");
-
- /** rdf:first */
- public static final IRI first = create("first");
-
- /** rdf:object */
+ /** object
**/
public static final IRI object = create("object");
- /** rdf:direction */
- public static final IRI direction = create("direction");
-
-
- // Individuals
- /** rdf:nil */
- public static final IRI nil = create("nil");
+ /** predicate
**/
+ public static final IRI predicate = create("predicate");
- /** rdf:rest */
+ /** rest
**/
public static final IRI rest = create("rest");
- /** rdf:predicate */
- public static final IRI predicate = create("predicate");
-
- /** rdf:subject */
+ /** subject
**/
public static final IRI subject = create("subject");
- /** rdf:language */
- public static final IRI language = create("language");
-
- /** rdf:type */
+ /** type
**/
public static final IRI type = create("type");
- /** rdf:value */
+ /** value
**/
public static final IRI value = create("value");
- /** rdf:first */
- public static final IRI first = create("first");
- /** rdf:object */
- public static final IRI object = create("object");
-
- /** rdf:direction */
- public static final IRI direction = create("direction");
+ // Individuals
+ /** nil
**/
+ public static final IRI nil = create("nil");
private static IRI create(String localName) {
diff --git a/src/test/resources/expected/testNoArgs/System.out b/src/test/resources/expected/testNoArgs/System.out
new file mode 100644
index 0000000..4960b45
--- /dev/null
+++ b/src/test/resources/expected/testNoArgs/System.out
@@ -0,0 +1,17 @@
+Missing required options: f, d, n, s, l, p, t
+usage: VocabGen
+ -a,--author Name of the java class author
+ -c,--copyright file containing the copyright snippet
+ -cp,--searchClasspath look for input files on classpath, then in
+ filesystem
+ -d,--doc Documentation URL
+ -f,--file OWL vocabulary file in TTL format
+ -jp,--package java package
+ -l,--long Long vocabulary name
+ -n,--ns Namespace URL
+ -o,--output-dir output directory
+ -p,--prefix Namespace prefix
+ -s,--short Short vocabulary name
+ -sc,--snake-case use all caps snake case constants instead of
+ as-is local names
+ -t,--template one of: rdf4j, jena, plain
diff --git a/src/test/resources/rdf-nolabels.ttl b/src/test/resources/rdf-nolabels.ttl
new file mode 100644
index 0000000..ed76bd6
--- /dev/null
+++ b/src/test/resources/rdf-nolabels.ttl
@@ -0,0 +1,132 @@
+@prefix rdf: .
+@prefix rdfs: .
+@prefix owl: .
+@prefix dc: .
+
+ a owl:Ontology ;
+ dc:title "The RDF Concepts Vocabulary (RDF)" ;
+ dc:date "2019-12-16" ;
+ dc:description "This is the RDF Schema for the RDF vocabulary terms in the RDF Namespace, defined in RDF 1.1 Concepts." .
+
+rdf:HTML a rdfs:Datatype ;
+ rdfs:subClassOf rdfs:Literal ;
+ rdfs:isDefinedBy ;
+ rdfs:seeAlso ;
+ rdfs:comment "The datatype of RDF literals storing fragments of HTML content" .
+
+rdf:langString a rdfs:Datatype ;
+ rdfs:subClassOf rdfs:Literal ;
+ rdfs:isDefinedBy ;
+ rdfs:seeAlso ;
+ rdfs:comment "The datatype of language-tagged string values" .
+
+rdf:PlainLiteral a rdfs:Datatype ;
+ rdfs:isDefinedBy ;
+ rdfs:subClassOf rdfs:Literal ;
+ rdfs:seeAlso ;
+ rdfs:comment "The class of plain (i.e. untyped) literal values, as used in RIF and OWL 2" .
+
+rdf:type a rdf:Property ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The subject is an instance of a class." ;
+ rdfs:range rdfs:Class ;
+ rdfs:domain rdfs:Resource .
+
+rdf:Property a rdfs:Class ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The class of RDF properties." ;
+ rdfs:subClassOf rdfs:Resource .
+
+rdf:Statement a rdfs:Class ;
+ rdfs:isDefinedBy ;
+ rdfs:subClassOf rdfs:Resource ;
+ rdfs:comment "The class of RDF statements." .
+
+rdf:subject a rdf:Property ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The subject of the subject RDF statement." ;
+ rdfs:domain rdf:Statement ;
+ rdfs:range rdfs:Resource .
+
+rdf:predicate a rdf:Property ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The predicate of the subject RDF statement." ;
+ rdfs:domain rdf:Statement ;
+ rdfs:range rdfs:Resource .
+
+rdf:object a rdf:Property ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The object of the subject RDF statement." ;
+ rdfs:domain rdf:Statement ;
+ rdfs:range rdfs:Resource .
+
+rdf:Bag a rdfs:Class ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The class of unordered containers." ;
+ rdfs:subClassOf rdfs:Container .
+
+rdf:Seq a rdfs:Class ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The class of ordered containers." ;
+ rdfs:subClassOf rdfs:Container .
+
+rdf:Alt a rdfs:Class ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The class of containers of alternatives." ;
+ rdfs:subClassOf rdfs:Container .
+
+rdf:value a rdf:Property ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "Idiomatic property used for structured values." ;
+ rdfs:domain rdfs:Resource ;
+ rdfs:range rdfs:Resource .
+
+rdf:List a rdfs:Class ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The class of RDF Lists." ;
+ rdfs:subClassOf rdfs:Resource .
+
+rdf:nil a rdf:List ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The empty list, with no items in it. If the rest of a list is nil then the list has no more items in it." .
+
+rdf:first a rdf:Property ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The first item in the subject RDF list." ;
+ rdfs:domain rdf:List ;
+ rdfs:range rdfs:Resource .
+
+rdf:rest a rdf:Property ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The rest of the subject RDF list after the first item." ;
+ rdfs:domain rdf:List ;
+ rdfs:range rdf:List .
+
+rdf:XMLLiteral a rdfs:Datatype ;
+ rdfs:subClassOf rdfs:Literal ;
+ rdfs:isDefinedBy ;
+ rdfs:comment "The datatype of XML literal values." .
+
+rdf:JSON a rdfs:Datatype ;
+ rdfs:comment "The datatype of RDF literals storing JSON content." ;
+ rdfs:subClassOf rdfs:Literal ;
+ rdfs:isDefinedBy ;
+ rdfs:seeAlso .
+
+rdf:CompoundLiteral a rdfs:Class ;
+ rdfs:comment "A class representing a compound literal." ;
+ rdfs:subClassOf rdfs:Resource ;
+ rdfs:isDefinedBy ;
+ rdfs:seeAlso .
+
+rdf:language a rdf:Property ;
+ rdfs:comment "The language component of a CompoundLiteral." ;
+ rdfs:domain rdf:CompoundLiteral ;
+ rdfs:isDefinedBy ;
+ rdfs:seeAlso .
+
+rdf:direction a rdf:Property ;
+ rdfs:comment "The base direction component of a CompoundLiteral." ;
+ rdfs:domain rdf:CompoundLiteral ;
+ rdfs:isDefinedBy ;
+ rdfs:seeAlso .