public static final File RESOURCE_DIR = new File("src/test/resources"); public static File constructTargetPath(File sourceFile, File fromDir, File toDir) {
  var targetFile = new File(
      replaceDirStem(sourceFile.getParentFile(), fromDir, toDir),
      sourceFile.getName());
  return makeDir(targetFile);
} @SuppressWarnings("ResultOfMethodCallIgnored")
public static File createDir(File parentDir, String name) {
  var newDir = new File(parentDir, name);
  newDir.mkdirs();
  return newDir;
} public static File createTempDir(File parent, String prefix) throws IOException {
  return Files.createTempDirectory(parent.toPath(), prefix).toFile();
} public static String getFileContents(File file, String encoding) throws IOException {
  return Files.readString(file.toPath(), Charset.forName(encoding));
} public static File getRawRdfDirectory() {
  var rawRdfDirectory = new File(RESOURCE_DIR.getPath() + "/" + ONTOLOGIES_DIR);
  assertTrue(rawRdfDirectory.isDirectory(), String.format("%s is not a directory", rawRdfDirectory));
  assertTrue(rawRdfDirectory.exists(), String.format("%s does not exists", rawRdfDirectory));
  return rawRdfDirectory;
} public static List<File> listDirTreeFiles(File dir) {
  var result = new ArrayList<File>();

  if (dir.exists()) {
    if (dir.isDirectory()) {
      for (var file : dir.listFiles()) {
        result.addAll(listDirTreeFiles(file));
      }
    } else {
      var isExcluded = listDirTreeFilesExcludeRegexes()
          .stream()
          .anyMatch(regex -> Pattern.compile(regex).matcher(dir.getName()).find());
      if (!isExcluded) {
        result.add(dir); // 'dir' is actually a file
      }
    }
  }

  return result;
} @SuppressWarnings("ResultOfMethodCallIgnored")
public static File mkCleanDir(String dirPath) {
  var newDir = new File(dirPath);
  if (newDir.exists()) {
    deleteFile(newDir);
  }
  newDir.mkdirs();
  return newDir;
} public static <T> T asInstanceOf(Object resource, Class<T> instanceType) {
  return instanceType.cast(resource);
} public static void assertTriplesMatch(Model model1, Model model2) {
  var maxWarnings = 3;

  var unmatchedTriples1to2 = new HashSet<Statement>();

  for (var st1 : model1) { // for each triple in model1, does it exist in model2?
    var triplesMatch1to2 = false;
    for (var st2 : model2) {
      if (!triplesMatch1to2) {
        if (triplesMatch(st1, st2, model1.getNamespaces(), model2.getNamespaces())) {
          triplesMatch1to2 = true;
        }
      }
    }

    // TODO: Add debugging logs
    if (!triplesMatch1to2) {
      unmatchedTriples1to2.add(st1);
      if (unmatchedTriples1to2.size() <= maxWarnings) {
        for (var st2Alt : model2) {
          if ((st1.getSubject() == st2Alt.getSubject()) ||
              (st1.getSubject() instanceof BNode && st2Alt.getSubject() instanceof BNode) ||
              (st1.getSubject() instanceof IRI && st2Alt.getSubject() instanceof IRI &&
                  (expandQNameToFullIriString(asInstanceOf(st1.getSubject(), IRI.class), model1.getNamespaces()))
                      .equals(expandQNameToFullIriString(asInstanceOf(st2Alt.getSubject(), IRI.class), model2.getNamespaces())))) {
            if ((st1.getPredicate() == st2Alt.getPredicate() ||
                (expandQNameToFullIriString(st1.getPredicate(), model1.getNamespaces())
                    .equals(expandQNameToFullIriString(st2Alt.getPredicate(), model2.getNamespaces()))))) {
              LOGGER.info("Possible object match: {}", st2Alt.getObject().stringValue());
            }
          }
        }
      }
    }
  }

  var unmatchedTriples2to1 = new HashSet<Statement>();
  for (var st2 : model2) { // for each triple in model2, does it exist in model1?
    var triplesMatch2to1 = false;
    for (var st1Alt : model1) {
      if (!triplesMatch2to1) {
        if (triplesMatch(st2, st1Alt, model1.getNamespaces(), model2.getNamespaces())) {
          triplesMatch2to1 = true;
        }
      }
    }

    if (!triplesMatch2to1) {
      unmatchedTriples2to1.add(st2);
      if (unmatchedTriples2to1.size() <= maxWarnings) {
        System.out.println("unmatched triple 2 to 1 [" + unmatchedTriples2to1.size() + ": " + st2 + "]");
      }
    }
  }

  assertTrue(
      unmatchedTriples1to2.isEmpty() && unmatchedTriples2to1.isEmpty(),
      String.format(
          "found unmatched triples: [%d], [%d]",
          unmatchedTriples1to2.size() / model1.size(),
          unmatchedTriples2to1.size() / model2.size()));
} public static boolean compareFiles(File file1, File file2, String encoding) throws IOException {
  // MAYBE: Log debugging info
  var source1Lines = readFileLines(file1, encoding).iterator();
  var source2Lines = readFileLines(file2, encoding).iterator();
  return compareStringIterators(source1Lines, source2Lines, file1, file2);
} public static Optional<String> getBaseIri(String line) {
  if (line.startsWith("# baseURI: ")) { // Turtle - TopBraid Composer
    return Optional.of(line.substring("# baseURI: ".length()));
  } else if (line.startsWith("@base ")) { // Turtle
    return Optional.of(line.replaceAll("@base\\s+<([^>]+)>.*", "$1"));
  } else if (line.contains("xml:base")) { // RDF/XML
    return Optional.of(line.replaceAll(".*xml:base\\s*=\\s*[\"']([^\"']+)[\"'].*", "$1"));
  } else if (line.contains("\"@base\"")) { // JSON-LD
    return Optional.of(line.replaceAll(".*\"@base\"\\s*:\\s*\"([^\"]+)\".*", "$1"));
  } else {
    return Optional.empty();
  }
} public static final Set<String> IBI_EXCLUSION_SET = Set.of("food.rdf", "wine.rdf"); public static final Set<String> INFERRED_BASE_IRI_EXCLUSION_SET = Set.of("food.rdf", "wine.rdf"); public static final Set<String> INLINE_BLANK_NODES_EXCLUSION_SET = Set.of(
    "allemang-FunctionalEntities.rdf",
    "turtle-example-14.ttl",
    "turtle-example-25.ttl",
    "turtle-example-26.ttl"); public static final Set<String> JSON_LD_INLINE_BLANK_NODES_EXCLUSION_SET = Set.of(
    "allemang-FunctionalEntities.rdf",
    "turtle-example-14.ttl",
    "turtle-example-25.ttl",
    "turtle-example-26.ttl"); public static final Set<String> RDFXML_EXCLUSION_SET = Set.of(
    "allemang-test-a.ttl",
    "allemang-test-b.ttl",
    "turtle-example-2.ttl",
    "turtle-example-3.ttl",
    "turtle-example-4.ttl",
    "turtle-example-5.ttl",
    "turtle-example-6.ttl",
    "turtle-example-9.ttl",
    "turtle-example-17.ttl",
    "turtle-example-22.ttl"); public static final String XS_STRING = XML_SCHEMA_NS_URI + "string"; public static final String BASE_IRI = "baseIri"; public static final String INDENT = "indent"; public static final String INLINE_BLANK_NODES = "inlineBlankNodes"; public static final String SHORT_URI_PREF = "shortUriPref"; public static final String USE_DTD_SUBSET = "useDtdSubset"; public class FileSystemUtils {

  public static final String ONTOLOGIES_DIR = "ontologies";
  public static final File RESOURCE_DIR = new File("src/test/resources");

  public static File constructTargetPath(File sourceFile, File fromDir, File toDir) {
    var targetFile = new File(
        replaceDirStem(sourceFile.getParentFile(), fromDir, toDir),
        sourceFile.getName());
    return makeDir(targetFile);
  }

  public static File constructTargetPath(File sourceFile, File fromDir, File toDir, String newStem) {
    var targetFile = new File(
        replaceDirStem(sourceFile.getParentFile(), fromDir, toDir),
        setFilePathExtension(sourceFile.getName(), newStem));
    return makeDir(targetFile);
  }

  public static File createTempDir(File parent, String prefix) throws IOException {
    return Files.createTempDirectory(parent.toPath(), prefix).toFile();
  }

  @SuppressWarnings("ResultOfMethodCallIgnored")
  public static File createDir(File parentDir, String name) {
    var newDir = new File(parentDir, name);
    newDir.mkdirs();
    return newDir;
  }

  public static List<File> listDirTreeFiles(File dir) {
    var result = new ArrayList<File>();

    if (dir.exists()) {
      if (dir.isDirectory()) {
        for (var file : dir.listFiles()) {
          result.addAll(listDirTreeFiles(file));
        }
      } else {
        var isExcluded = listDirTreeFilesExcludeRegexes()
            .stream()
            .anyMatch(regex -> Pattern.compile(regex).matcher(dir.getName()).find());
        if (!isExcluded) {
          result.add(dir); // 'dir' is actually a file
        }
      }
    }

    return result;
  }

  /**
   * Creates a clean directory at the given path.  Deletes any existing contents.
   */
  @SuppressWarnings("ResultOfMethodCallIgnored")
  public static File mkCleanDir(String dirPath) {
    var newDir = new File(dirPath);
    if (newDir.exists()) {
      deleteFile(newDir);
    }
    newDir.mkdirs();
    return newDir;
  }

  /**
   * Deletes the given file or directory.  For a directory, deletes recursively.
   */
  @SuppressWarnings("ResultOfMethodCallIgnored")
  public static void deleteFile(File file) {
    if (file.isDirectory()) {
      for (File childFile : file.listFiles()) {
        deleteFile(childFile);
      }
    }
    file.delete();
  }

  public static String getFileContents(File file, String encoding) throws IOException {
    return Files.readString(file.toPath(), Charset.forName(encoding));
  }

  public static List<String> readFileLines(File file, String encoding) throws IOException {
    return Files.readAllLines(file.toPath(), Charset.forName(encoding));
  }

  public static Set<String> listDirTreeFilesExcludeRegexes() {
    return Set.of("\\.conf", "^About", "catalog\\d+\\.xml");
  }

  public static File getRawRdfDirectory() {
    var rawRdfDirectory = new File(RESOURCE_DIR.getPath() + "/" + ONTOLOGIES_DIR);
    assertTrue(rawRdfDirectory.isDirectory(), String.format("%s is not a directory", rawRdfDirectory));
    assertTrue(rawRdfDirectory.exists(), String.format("%s does not exists", rawRdfDirectory));
    return rawRdfDirectory;
  }

  @SuppressWarnings("ResultOfMethodCallIgnored")
  private static File makeDir(File targetFile) {
    if (!targetFile.getParentFile().exists()) {
      targetFile.getParentFile().mkdirs();
    }
    return targetFile;
  }

  private static File replaceDirStem(File file, File fromDir, File toDir) {
    try {
      var filePath = file.getCanonicalPath();
      var fromDirPath = fromDir.getCanonicalPath();
      var toDirPath = toDir.getCanonicalPath();
      if (filePath.startsWith(fromDirPath)) {
        return new File(toDirPath + filePath.substring(fromDirPath.length()));
      } else {
        return file;
      }
    } catch (IOException ex) {
      fail(ex.getClass().getSimpleName() + " occurred while replacing dir stem. Details: " + ex.getMessage());
      return null;
    }
  }

  private static String setFilePathExtension(String filePath, String fileExtension) {
    if (filePath.contains(".")) {
      return filePath.substring(0, filePath.lastIndexOf(".")) + fileExtension;
    } else {
      return filePath + fileExtension;
    }
  }
} public class RdfFormatter {

  private static final Logger logger = LoggerFactory.getLogger(RdfFormatter.class);

  /**
   * Main method for running the RDF formatter. Run with "--help" option for help.
   */
  public static void main(String[] args) {
    try {
      run(args);
      System.exit(0);
    } catch (Exception ex) {
      logger.error("{}: stopped by unexpected exception: ", RdfFormatter.class.getSimpleName());
      logger.error("{}: {}", ex.getClass().getSimpleName(), ex.getMessage());
      var stackTraceWriter = new StringWriter();
      ex.printStackTrace(new PrintWriter(stackTraceWriter));
      logger.error(stackTraceWriter.toString());
      System.exit(1);
    }
  }

  /**
   * Main method, but throws exceptions for use from inside other Java code.
   */
  public static void run(String[] args) throws Exception {
    var rdfToolkitRunner = new RdfToolkitRunner();
    rdfToolkitRunner.run(args);
  }
} public enum TargetFormats {
  JSON_LD("json-ld", "(JSON-LD)", RDFFormat.JSONLD),
  RDF_XML("rdf-xml", "(RDF/XML)", RDFFormat.RDFXML),
  TURTLE("turtle", "(Turtle)", RDFFormat.TURTLE);

  public static final TargetFormats DEFAULT_FORMAT = TURTLE;

  private final String optionValue;
  private final String optionComment;
  private final RDFFormat rdfFormat;

  TargetFormats(String optionValue, String optionComment, RDFFormat rdfFormat) {
    this.optionValue = optionValue;
    this.optionComment = optionComment;
    this.rdfFormat = rdfFormat;
  }

  public String getOptionValue() {
    return optionValue;
  }

  public String getOptionComment() {
    return optionComment;
  }

  public RDFFormat getRDFFormat() {
    return rdfFormat;
  }

  public static TargetFormats getByOptionValue(String optionValue) {
    if (optionValue == null) {
      return null;
    }
    for (TargetFormats tfmt : values()) {
      if (optionValue.equals(tfmt.optionValue)) {
        return tfmt;
      }
    }
    return null;
  }

  public static String summarise() {
    ArrayList<String> result = new ArrayList<>();
    for (TargetFormats tfmt : values()) {
      String value = tfmt.optionValue;
      if (tfmt.optionComment != null) {
        value += " " + tfmt.optionComment;
      }
      if (DEFAULT_FORMAT.equals(tfmt)) {
        value += " [default]";
      }
      result.add(value);
    }
    return String.join(", ", result);
  }
} public enum ShortIriPreferences {

  PREFIX("prefix"),
  BASE_IRI("base-iri");

  private static final ShortIriPreferences defaultEnum = PREFIX;

  private final String optionValue;

  ShortIriPreferences(String optionValue) {
    this.optionValue = optionValue;
  }

  public String getOptionValue() {
    return optionValue;
  }

  public static ShortIriPreferences getByOptionValue(String optionValue) {
    if (optionValue == null) {
      return null;
    }
    for (ShortIriPreferences sup : ShortIriPreferences.values()) {
      if (optionValue.equals(sup.optionValue)) {
        return sup;
      }
    }
    return null;
  }

  public static String summarise() {
    List<String> result = new ArrayList<>();
    for (ShortIriPreferences sup : ShortIriPreferences.values()) {
      String value = sup.optionValue;
      if (defaultEnum.equals(sup)) {
        value += " [default]";
      }
      result.add(value);
    }
    return String.join(", ", result);
  }
}
import static org.edmcouncil.rdf_toolkit.FileSystemUtils.RESOURCE_DIR;
import static org.edmcouncil.rdf_toolkit.FileSystemUtils.constructTargetPath;
import static org.edmcouncil.rdf_toolkit.FileSystemUtils.createDir;
import static org.edmcouncil.rdf_toolkit.FileSystemUtils.createTempDir;
import static org.edmcouncil.rdf_toolkit.FileSystemUtils.getFileContents;
import static org.edmcouncil.rdf_toolkit.FileSystemUtils.getRawRdfDirectory;
import static org.edmcouncil.rdf_toolkit.FileSystemUtils.listDirTreeFiles;
import static org.edmcouncil.rdf_toolkit.FileSystemUtils.mkCleanDir;
import static org.edmcouncil.rdf_toolkit.TestComparisonsUtils.asInstanceOf;
import static org.edmcouncil.rdf_toolkit.TestComparisonsUtils.assertTriplesMatch;
import static org.edmcouncil.rdf_toolkit.TestComparisonsUtils.compareFiles;
import static org.edmcouncil.rdf_toolkit.TestComparisonsUtils.getBaseIri;
import static org.edmcouncil.rdf_toolkit.TestConstants.IBI_EXCLUSION_SET;
import static org.edmcouncil.rdf_toolkit.TestConstants.INFERRED_BASE_IRI_EXCLUSION_SET;
import static org.edmcouncil.rdf_toolkit.TestConstants.INLINE_BLANK_NODES_EXCLUSION_SET;
import static org.edmcouncil.rdf_toolkit.TestConstants.JSON_LD_INLINE_BLANK_NODES_EXCLUSION_SET;
import static org.edmcouncil.rdf_toolkit.TestConstants.RDFXML_EXCLUSION_SET;
import static org.edmcouncil.rdf_toolkit.TestConstants.XS_STRING;
import static org.edmcouncil.rdf_toolkit.util.Constants.BASE_IRI;
import static org.edmcouncil.rdf_toolkit.util.Constants.INDENT;
import static org.edmcouncil.rdf_toolkit.util.Constants.INLINE_BLANK_NODES;
import static org.edmcouncil.rdf_toolkit.util.Constants.SHORT_URI_PREF;
import static org.edmcouncil.rdf_toolkit.util.Constants.USE_DTD_SUBSET;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.RDFWriter;
import org.eclipse.rdf4j.rio.Rio;
import org.eclipse.rdf4j.rio.rdfxml.util.RDFXMLPrettyWriterFactory;
import org.edmcouncil.rdf_toolkit.FileSystemUtils;
import org.edmcouncil.rdf_toolkit.RdfFormatter;
import org.edmcouncil.rdf_toolkit.io.format.TargetFormats;
import org.edmcouncil.rdf_toolkit.util.ShortIriPreferences;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Optional;
    outWriter2.close();
    assertTrue(
        outputFile2.exists(),
        String.format("File '%s' should exists after writing.", outputFile2.getAbsolutePath()));
  }

  @Test
  void shouldBeAbleToProduceSortedRdfXmlFileWithIndirectlyRecursiveBlankObjectNodes() throws Exception {
    var rawRdfDirectory = getRawRdfDirectory();
    var outputDir1 = createTempDir(rootOutputDir1, RDFXML_PREFIX);
    var outputDir2 = createTempDir(rootOutputDir2, outputDir1.getName());
    var inputFile = new File(rawRdfDirectory.getPath() + "/rdf_turtle_spec/turtle-example-26.ttl");
    var outputFile = FileSystemUtils.constructTargetPath(inputFile, rawRdfDirectory, outputDir1, RDFXML_STEM);
    var outWriter = new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8.name());
    var factory = new SortedRdfWriterFactory(TargetFormats.RDF_XML);
    Map<String, Object> rdfXmlWriterOptions = Map.of(USE_DTD_SUBSET, true);
    var rdfXmlWriter = factory.getWriter(outWriter, rdfXmlWriterOptions);

    var inputModel = Rio.parse(new FileReader(inputFile), "", RDFFormat.TURTLE);
    Rio.write(inputModel, rdfXmlWriter);
    outWriter.flush();
    outWriter.close();
    assertTrue(
        outputFile.exists(),
        String.format("File '%s' should exists after writing.", outputFile.getAbsolutePath()));

    var outputFile2 = constructTargetPath(outputFile, outputDir1, outputDir2);
    var outWriter2 = new OutputStreamWriter(new FileOutputStream(outputFile2), StandardCharsets.UTF_8.name());
    Map<String, Object> rdfXmlWriter2Options = Map.of(USE_DTD_SUBSET, true);
    var rdfXmlWriter2 = factory.getWriter(outWriter2, rdfXmlWriter2Options);

    var inputModel2 = Rio.parse(
        new InputStreamReader(new FileInputStream(outputFile), StandardCharsets.UTF_8.name()),
        "",
        RDFFormat.RDFXML);
    Rio.write(inputModel2, rdfXmlWriter2);
    outWriter2.flush();
    outWriter2.close();
    assertTrue(
        outputFile2.exists(),
        String.format("File '%s' should exists after writing.", outputFile2.getAbsolutePath()));
  }

  @Test
  void shouldBeAbleToProduceSortedRdfXmlFilePreferringPrefixOverBaseIri() throws Exception {
    var outputDir1 = createTempDir(rootOutputDir1, RDFXML_PREFIX);
    var outputDir2 = createTempDir(rootOutputDir2, outputDir1.getName());
    var inputFile = new File(getRawRdfDirectory().getPath() + "/other/topbraid-countries-ontology.ttl");
    var baseIri = valueFactory.createIRI("http://topbraid.org/countries");
    var outputFile = FileSystemUtils.constructTargetPath(inputFile, getRawRdfDirectory(), outputDir1, "_prefix.rdf");
    var outWriter = new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8.name());
    var factory = new SortedRdfWriterFactory(TargetFormats.RDF_XML);
    Map<String, Object> rdfXmlWriterOptions = Map.of(USE_DTD_SUBSET, true);
    var rdfXmlWriter = factory.getWriter(outWriter, rdfXmlWriterOptions);

    var inputModel = Rio.parse(new FileReader(inputFile), baseIri.stringValue(), RDFFormat.TURTLE);
    Rio.write(inputModel, rdfXmlWriter);
    outWriter.flush();
    outWriter.close();
    var contents1 = getFileContents(outputFile, StandardCharsets.UTF_8.name());
    assertTrue(contents1.contains("Åland"), "prefix preference file has encoding problem (1)");

    var outputFile2 = constructTargetPath(outputFile, outputDir1, outputDir2);
    var outWriter2 = new OutputStreamWriter(new FileOutputStream(outputFile2), StandardCharsets.UTF_8.name());
    Map<String, Object> rdfXmlWriter2Options = Map.of(USE_DTD_SUBSET, true);
    var rdfXmlWriter2 = factory.getWriter(outWriter2, rdfXmlWriter2Options);

    var inputModel2 = Rio.parse(
        new InputStreamReader(new FileInputStream(outputFile), StandardCharsets.UTF_8.name()),
        baseIri.stringValue(),
        RDFFormat.RDFXML);
    Rio.write(inputModel2, rdfXmlWriter2);
    var contents2 = getFileContents(outputFile2, StandardCharsets.UTF_8.name());
    assertTrue(contents2.contains("Åland"), "prefix preference file has encoding problem (2)");
    outWriter2.flush();
    outWriter2.close();
  }

  @Test
  void shouldBeAbleToProduceSortedRdfXmlFilePreferringBaseIriOverPrefix() throws Exception {
    var outputDir1 = createTempDir(rootOutputDir1, RDFXML_PREFIX);
    var outputDir2 = createTempDir(rootOutputDir2, outputDir1.getName());
    var inputFile = new File(getRawRdfDirectory().getPath() + "/other/topbraid-countries-ontology.ttl");
    var baseIri = valueFactory.createIRI("http://topbraid.org/countries");
    var outputFile = FileSystemUtils.constructTargetPath(inputFile, getRawRdfDirectory(), outputDir1, "_base_iri.rdf");
    var outWriter = new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8.name());
    var factory = new SortedRdfWriterFactory(TargetFormats.RDF_XML);
    Map<String, Object> rdfXmlWriterOptions = Map.of(USE_DTD_SUBSET, true);
    var rdfXmlWriter = factory.getWriter(outWriter, rdfXmlWriterOptions);

    var inputModel = Rio.parse(new FileReader(inputFile), baseIri.stringValue(), RDFFormat.TURTLE);
    Rio.write(inputModel, rdfXmlWriter);
    outWriter.flush();
    outWriter.close();
    var contents1 = getFileContents(outputFile, StandardCharsets.UTF_8.name());
    assertTrue(contents1.contains("Åland"), "base IRI preference file has encoding problem (1)");

    var outputFile2 = constructTargetPath(outputFile, outputDir1, outputDir2);
    var outWriter2 = new OutputStreamWriter(new FileOutputStream(outputFile2), StandardCharsets.UTF_8.name());
    Map<String, Object> rdfXmlWriter2Options = Map.of(USE_DTD_SUBSET, true);
    var rdfXmlWriter2 = factory.getWriter(outWriter2, rdfXmlWriter2Options);

    var inputModel2 = Rio.parse(
        new InputStreamReader(new FileInputStream(outputFile), StandardCharsets.UTF_8.name()),
        baseIri.stringValue(),
        RDFFormat.RDFXML);
    Rio.write(inputModel2, rdfXmlWriter2);
    var contents2 = getFileContents(outputFile2, StandardCharsets.UTF_8.name());
    assertTrue(contents2.contains("Åland"), "base IRI preference file has encoding problem (2)");
    outWriter2.flush();
    outWriter2.close();
  }

  @Test
  void shouldBeAbleToReadVariousRdfDocumentsAndWriteThemInSortedRdfXmlFormat() throws Exception {
    var rawRdfDirectory = getRawRdfDirectory();
    var rootOutputDir = createTempDir(rootOutputDir1, RDFXML_PREFIX);

    var fileCount = 0;
    for (File sourceFile : listDirTreeFiles(rawRdfDirectory)) {
      if (!RDFXML_EXCLUSION_SET.contains(sourceFile.getName())) {