Fixing ZUGFeRD 1.0 to 2.0 XSL transformation by adding latest SAXON. In addition, adding JUnit test, some copyright header, etc.
This commit is contained in:
@@ -1,89 +1,99 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* Copyright 2018 Jochen Staerk
|
||||
*
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at http://www.apache.org/licenses/LICENSE-2.0. You can also
|
||||
* obtain a copy of the License at http://odftoolkit.org/docs/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*********************************************************************** */
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Templates;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.URIResolver;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
|
||||
|
||||
public class ZUGFeRDMigrator {
|
||||
static final ClassLoader cl = ZUGFeRDMigrator.class.getClassLoader();
|
||||
private static TransformerFactory factory = null;
|
||||
private static final String resourcePath = ""; //$NON-NLS-1$
|
||||
|
||||
private static TransformerFactory getTransformerFactory() {
|
||||
//TransformerFactory fact = new net.sf.saxon.TransformerFactoryImpl();
|
||||
TransformerFactory fact = TransformerFactory.newInstance();
|
||||
fact.setURIResolver(new ClasspathResourceURIResolver());
|
||||
return fact;
|
||||
}
|
||||
public String migrateFromV1ToV2(String xmlFilename) {
|
||||
/***
|
||||
* http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf
|
||||
* http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf
|
||||
http://countwordsfree.com/xmlviewer
|
||||
*/
|
||||
ByteArrayOutputStream baos=new ByteArrayOutputStream();
|
||||
try {
|
||||
applySchematronXsl(new FileInputStream(xmlFilename), baos);
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (TransformerException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
String res=null;
|
||||
try {
|
||||
res=baos.toString("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
static final ClassLoader CLASS_LOADER = ZUGFeRDMigrator.class.getClassLoader();
|
||||
private static final String RESOURCE_PATH = ""; //$NON-NLS-1$
|
||||
private static final Logger LOG = Logger.getLogger(ZUGFeRDMigrator.class.getName());
|
||||
// private static File createTempFileResult(final Transformer transformer, final StreamSource toTransform,
|
||||
// final String suffix) throws TransformerException, IOException {
|
||||
// File result = File.createTempFile("ZUV_", suffix); //$NON-NLS-1$
|
||||
// result.deleteOnExit();
|
||||
//
|
||||
// try (FileOutputStream fos = new FileOutputStream(result)) {
|
||||
// transformer.transform(toTransform, new StreamResult(fos));
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
private TransformerFactory mFactory = null;
|
||||
private Templates mXsltTemplate = null;
|
||||
|
||||
private static File createTempFileResult(final Transformer transformer, final StreamSource toTransform,
|
||||
final String suffix) throws TransformerException, IOException {
|
||||
File result = File.createTempFile("ZUV_", suffix); //$NON-NLS-1$
|
||||
result.deleteOnExit();
|
||||
public ZUGFeRDMigrator() {
|
||||
mFactory = new net.sf.saxon.TransformerFactoryImpl();
|
||||
//fact = TransformerFactory.newInstance();
|
||||
mFactory.setURIResolver(new ClasspathResourceURIResolver());
|
||||
try {
|
||||
mXsltTemplate = mFactory.newTemplates(new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "COMFORTtoEN16931.xsl")));
|
||||
} catch (TransformerConfigurationException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(result)) {
|
||||
transformer.transform(toTransform, new StreamResult(fos));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class ClasspathResourceURIResolver implements URIResolver {
|
||||
ClasspathResourceURIResolver() {
|
||||
// Do nothing, just prevents synthetic access warning.
|
||||
}
|
||||
public String migrateFromV1ToV2(String xmlFilename) throws FileNotFoundException, TransformerException, UnsupportedEncodingException {
|
||||
/**
|
||||
* *
|
||||
* http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf
|
||||
* http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf
|
||||
* http://countwordsfree.com/xmlviewer
|
||||
*/
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
applySchematronXsl(new FileInputStream(xmlFilename), baos);
|
||||
String res = null;
|
||||
res = baos.toString("UTF-8");
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Source resolve(String href, String base) throws TransformerException {
|
||||
return new StreamSource(cl.getResourceAsStream(resourcePath + href));
|
||||
}
|
||||
}
|
||||
|
||||
public static void applySchematronXsl(final InputStream xmlFile,
|
||||
final OutputStream EN16931Outstream) throws TransformerException {
|
||||
factory=getTransformerFactory();
|
||||
Transformer transformer = factory.newTransformer(new StreamSource(cl.getResourceAsStream(resourcePath+"COMFORTtoEN16931.xsl")));
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(EN16931Outstream));
|
||||
}
|
||||
public void applySchematronXsl(final InputStream xmlFile,
|
||||
final OutputStream EN16931Outstream) throws TransformerException {
|
||||
Transformer transformer = mXsltTemplate.newTransformer();
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(EN16931Outstream));
|
||||
}
|
||||
|
||||
private static class ClasspathResourceURIResolver implements URIResolver {
|
||||
ClasspathResourceURIResolver() {
|
||||
// Do nothing, just prevents synthetic access warning.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Source resolve(String href, String base) throws TransformerException {
|
||||
return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + href));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,23 @@ package org.mustangproject.toecount;
|
||||
|
||||
/***
|
||||
* This is the command line interface to mustangproject
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
import com.sanityinc.jargs.CmdLineParser;
|
||||
import com.sanityinc.jargs.CmdLineParser.Option;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDConformanceLevel;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDExporter;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory;
|
||||
@@ -20,9 +26,6 @@ import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA3Factory;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDMigrator;
|
||||
|
||||
import com.sanityinc.jargs.CmdLineParser;
|
||||
import com.sanityinc.jargs.CmdLineParser.Option;
|
||||
|
||||
public class Toecount {
|
||||
// build with: /opt/local/bin/mvn clean compile assembly:single
|
||||
private static void printUsage() {
|
||||
@@ -53,7 +56,7 @@ public class Toecount {
|
||||
/***
|
||||
* Asks the user for a String (offering a defaultValue) conforming to a Regex
|
||||
* pattern
|
||||
*
|
||||
*
|
||||
* @param prompt
|
||||
* @param defaultValue
|
||||
* @param pattern
|
||||
@@ -98,10 +101,10 @@ public class Toecount {
|
||||
* Prompts the user for a input or output filename
|
||||
* @param prompt
|
||||
* @param defaultFilename
|
||||
* @param expectedExtension will warn if filename does not match expected file extension
|
||||
* @param expectedExtension will warn if filename does not match expected file extension
|
||||
* @param ensureFileExists will warn if file does NOT exist (for input files)
|
||||
* @param ensureFileNotExists will warn if file DOES exist (for output files)
|
||||
*
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
protected static String getFilenameFromUser(String prompt, String defaultFilename, String expectedExtension, boolean ensureFileExists, boolean ensureFileNotExists) {
|
||||
@@ -147,7 +150,7 @@ public class Toecount {
|
||||
System.out.println("File does not exist, try again or CTRL+C to cancel");
|
||||
// discard the input, a scanner.reset is not sufficient
|
||||
fileExistenceOK = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fileExistenceOK=true;
|
||||
|
||||
@@ -158,7 +161,7 @@ public class Toecount {
|
||||
System.out.println("Output file already exists, try again or CTRL+C to cancel");
|
||||
// discard the input, a scanner.reset is not sufficient
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fileExistenceOK=true;
|
||||
}
|
||||
@@ -275,12 +278,12 @@ public class Toecount {
|
||||
String versionInput = "";
|
||||
try {
|
||||
versionInput = getStringFromUser("ZUGFeRD version (1 or 2)", "1", "1|2");
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
String profileInput = "";
|
||||
int zfIntVersion=Integer.valueOf(versionInput);
|
||||
|
||||
@@ -288,7 +291,7 @@ public class Toecount {
|
||||
if (zfIntVersion==1) {
|
||||
try {
|
||||
profileInput = getStringFromUser("ZUGFeRD profile b)asic, c)omfort or e)xtended", "e", "B|b|C|c|E|e").toLowerCase();
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
@@ -296,17 +299,17 @@ public class Toecount {
|
||||
if (profileInput.equals("b")) {
|
||||
profile=ZUGFeRDConformanceLevel.BASIC;
|
||||
} else if (profileInput.equals("c")) {
|
||||
profile=ZUGFeRDConformanceLevel.COMFORT;
|
||||
profile=ZUGFeRDConformanceLevel.COMFORT;
|
||||
} else if (profileInput.equals("e")) {
|
||||
profile=ZUGFeRDConformanceLevel.EXTENDED;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else if (zfIntVersion==2) {
|
||||
try {
|
||||
profileInput = getStringFromUser("ZUGFeRD profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" +
|
||||
profileInput = getStringFromUser("ZUGFeRD profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" +
|
||||
"[C]IUS, [E]N16931, E[X]TENDED", "E", "M|m|W|w|B|b|C|c|E|e|X|x|").toLowerCase();
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
@@ -314,7 +317,7 @@ public class Toecount {
|
||||
if (profileInput.equals("m")) {
|
||||
profile=ZUGFeRDConformanceLevel.MINIMUM;
|
||||
} else if (profileInput.equals("w")) {
|
||||
profile=ZUGFeRDConformanceLevel.BASICWL;
|
||||
profile=ZUGFeRDConformanceLevel.BASICWL;
|
||||
} else if (profileInput.equals("b")) {
|
||||
profile=ZUGFeRDConformanceLevel.BASIC;
|
||||
} else if (profileInput.equals("c")) {
|
||||
@@ -324,13 +327,13 @@ public class Toecount {
|
||||
} else if (profileInput.equals("x")) {
|
||||
profile=ZUGFeRDConformanceLevel.EXTENDED;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("Toecount")
|
||||
.setCreator(System.getProperty("user.name")).setZUGFeRDConformanceLevel(profile).load(pdfName);
|
||||
ze.setZUGFeRDVersion(zfIntVersion);
|
||||
|
||||
|
||||
ze.setZUGFeRDXMLData(Files.readAllBytes(Paths.get(xmlName)));
|
||||
|
||||
ze.export(outName);
|
||||
@@ -373,21 +376,25 @@ public class Toecount {
|
||||
}
|
||||
System.out.println("Written to " + outName);
|
||||
} else if (upgradeRequested) {
|
||||
String xmlName = "";
|
||||
String outName = "";
|
||||
try {
|
||||
String xmlName = "";
|
||||
String outName = "";
|
||||
|
||||
try {
|
||||
xmlName = getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false);
|
||||
outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "factur-x.xml", "xml", false, true);
|
||||
|
||||
ZUGFeRDMigrator zmi = new ZUGFeRDMigrator();
|
||||
String xml = zmi.migrateFromV1ToV2(xmlName);
|
||||
Files.write(Paths.get(outName), xml.getBytes());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("Written to " + outName);
|
||||
xmlName = getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false);
|
||||
outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "factur-x.xml", "xml", false, true);
|
||||
|
||||
ZUGFeRDMigrator zmi = new ZUGFeRDMigrator();
|
||||
String xml = null;
|
||||
xml = zmi.migrateFromV1ToV2(xmlName);
|
||||
Files.write(Paths.get(outName), xml.getBytes());
|
||||
System.out.println("Written to " + outName);
|
||||
} catch (FileNotFoundException ex) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (TransformerException | UnsupportedEncodingException ex) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
} else {
|
||||
// no argument or argument unknown
|
||||
printUsage();
|
||||
|
||||
Reference in New Issue
Block a user