diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java index e81032a3..f676e413 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java @@ -122,6 +122,10 @@ public class ZUGFeRDExporter implements Closeable { } ZFVersion = ver; } + + public IXMLProvider getProvider() { + return xmlProvider; + } private void init() { setZUGFeRDVersion(2); diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java index 8d07879f..5b343029 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java @@ -1,136 +1,87 @@ package org.mustangproject.ZUGFeRD; -public class ZUGFeRDMigrator { +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; - public String migrateFromV1ToV2(String xml) { +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +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 final TransformerFactory factory = getTransformerFactory(); + private static final String resourcePath = ""; //$NON-NLS-1$ + + private static TransformerFactory getTransformerFactory() { + 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 */ - // todo: attributes may also be in single quotes, this one hardcodedly expects - // double ones - xml = xml.replace("\"urn:ferd:CrossIndustryDocument:invoice:1p0", - "\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"); - xml = xml.replace("urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12", - "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"); - xml = xml.replace("urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15", - "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"); - xml = xml.replace("rsm:CrossIndustryDocument", "rsm:CrossIndustryInvoice"); - - xml = xml.replace("rsm:SpecifiedExchangedDocumentContext", "rsm:ExchangedDocumentContext"); - xml = xml.replace("rsm:HeaderExchangedDocument", "rsm:ExchangedDocument"); - xml = xml.replace("rsm:SpecifiedSupplyChainTradeTransaction", "rsm:SupplyChainTradeTransaction"); - xml = xml.replace("ram:ApplicableSupplyChainTradeAgreement", "ram:ApplicableHeaderTradeAgreement"); - xml = xml.replace("ram:ApplicableSupplyChainTradeDelivery", "ram:ApplicableHeaderTradeDelivery"); - xml = xml.replace("ram:ApplicableSupplyChainTradeSettlement", "ram:ApplicableHeaderTradeSettlement"); - xml = xml.replace("ram:ApplicablePercent", "ram:RateApplicablePercent"); - xml = xml.replace("ram:SpecifiedSupplyChainTradeDelivery", "ram:SpecifiedLineTradeDelivery"); - xml = xml.replace("ram:SpecifiedSupplyChainTradeSettlement", "ram:SpecifiedLineTradeSettlement"); - xml = xml.replace("ram:SpecifiedTradeSettlementMonetarySummation", "ram:SpecifiedTradeSettlementLineMonetarySummation"); - //xml = xml.replace("ram:SpecifiedTradeSettlementLineMonetarySummation", "ram:SpecifiedTradeSettlementHeaderMonetarySummation"); - //ram:SpecifiedTradeSettlementLineMonetarySummation bleibt unterhalb von ram:SpecifiedLineTradeSettlement - //xml = xml.replace("ram:IssueDateTime","ram:FormattedIssueDateTime"); - xml = xml.replace("ram:SpecifiedTradeAccountingAccount","ram:SalesSpecifiedTradeAccountingAccount"); - xml = xml.replace("ram:SpecifiedSupplyChainTradeAgreement","ram:SpecifiedLineTradeAgreement"); - //xml = xml.replace("ram:ID","ram:GlobalID"); - - //ram:ID unterhalb von ram:ContractReferencedDocument zu ram:IssuerAssignedID - - //http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf - /* - xml = xml.replace("rsm:SpecifiedExchangedDocumentContext", "rsm:CIExchangedDocumentContext"); - xml = xml.replace("rsm:HeaderExchangedDocument", "rsm:CIIHExchangedDocument"); - xml = xml.replace("SpecifiedSupplyChainTradeTransaction", "CIIHSupplyChainTradeTransaction"); - xml = xml.replace("ram:GuidelineSpecifiedDocumentContextParameter", - "ram:GuidelineSpecifiedCIDocumentContextParameter"); - xml = xml.replace("ram:IncludedNote", "ram:IncludedCINote"); - xml = xml.replace("ram:ApplicableSupplyChainTradeAgreement", "ram:ApplicableCIIHSupplyChainTradeAgreement"); - xml = xml.replace("ram:SellerTradeParty", "ram:SellerCITradeParty"); - xml = xml.replace("ram:BuyerTradeParty", "ram:BuyerCITradeParty"); - xml = xml.replace("ram:ApplicableSupplyChainTradeDelivery", "ram:ApplicableCIIHSupplyChainTradeDelivery"); - xml = xml.replace("ram:ApplicableSupplyChainTradeSettlement", "ram:ApplicableCIIHSupplyChainTradeSettlement"); - xml = xml.replace("ram:IncludedSupplyChainTradeLineItem", "ram:IncludedCIILSupplyChainTradeLineItem"); - xml = xml.replace("ram:AssociatedDocumentLineDocument", "ram:AssociatedCIILDocumentLineDocument"); - xml = xml.replace("ram:SpecifiedSupplyChainTradeDelivery", "ram:SpecifiedCIILSupplyChainTradeDelivery"); - xml = xml.replace("ram:SpecifiedSupplyChainTradeSettlement", "ram:SpecifiedCIILSupplyChainTradeSettlement"); - xml = xml.replace("ram:SpecifiedTradeProduct", "ram:SpecifiedCITradeProduct"); - xml = xml.replace("ram:ActualDeliverySupplyChainEvent", "ram:ActualDeliveryCISupplyChainEvent"); - xml = xml.replace("ram:SpecifiedTradeSettlementPaymentMeans", "ram:SpecifiedCITradeSettlementPaymentMeans"); - xml = xml.replace("ram:PayeePartyCreditorFinancialAccount", "ram:PayeePartyCICreditorFinancialAccount"); - xml = xml.replace("ram:PayeeSpecifiedCreditorFinancialInstitution", - "ram:PayeeSpecifiedCICreditorFinancialInstitution"); - xml = xml.replace("ram:ApplicableTradeTax", "ram:ApplicableCITradeTax"); - xml = xml.replace("ram:ApplicablePercent", "ram:RateApplicablePercent"); - xml = xml.replace("ram:PostalTradeAddress", "ram:PostalCITradeAddress"); - - xml = xml.replace("ram:ApplicableTradePaymentDiscountTerms", "ram:ApplicableCITradePaymentDiscountTerms"); - xml = xml.replace("ram:ApplicableProductCharacteristic", "ram:ApplicableCIProductCharacteristic"); - xml = xml.replace("ram:ShipToTradeParty", "ram:ShipToCITradeParty"); - xml = xml.replace("ram:ShipFromTradeParty", "ram:ShipFromCITradeParty"); - xml = xml.replace("ram:ReceivableSpecifiedTradeAccountingAccount", - "ram:ReceivableSpecifiedCITradeAccountingAccount"); - xml = xml.replace("ram:ContractReferencedDocument", "ram:ContractReferencedCIReferencedDocument"); - // "ram:SpecifiedTradeAccountingAccount ram:SalesSpecifiedTradeAccountingAccount - // oder ReceivablesSpecifiedTradeAccountingAccount oder - // PurchaseSpecifiedTradeAccountingAccount - xml = xml.replace("ram:AdditionalReferencedDocument", "ram:AdditionalReferencedCIReferencedDocument"); - xml = xml.replace("ram:TelephoneUniversalCommunication", "ram:TelephoneCIUniversalCommunication"); - xml = xml.replace("ram:EmailURIUniversalCommunication", "ram:EmailURICIUniversalCommunication"); - xml = xml.replace("ram:AdditionalReferencedDocument", "ram:AdditionalReferencedCIReferencedDocument"); - xml = xml.replace("ram:IncludedReferencedProduct", "ram:IncludedReferencedProduct"); - - xml = xml.replace("ram:DefinedTradeContact", "ram:DefinedCITradeContact"); - xml = xml.replace("ram:BillingSpecifiedPeriod", "ram:BillingCISpecifiedPeriod"); - xml = xml.replace("ram:BuyerOrderReferencedDocument", "ram:BuyerOrderReferencedCIReferencedDocument"); - xml = xml.replace("ram:DeliveryNoteReferencedDocument", "ram:DeliveryNoteReferencedCIReferencedDocument"); - xml = xml.replace("ram:SpecifiedTradeAllowanceCharge", "ram:SpecifiedCITradeAllowanceCharge"); - xml = xml.replace("ram:SpecifiedLogisticsServiceCharge", "ram:SpecifiedCILogisticsServiceCharge"); - xml = xml.replace("ram:AppliedTradeAllowanceCharge", "ram:AppliedCITradeAllowanceCharge"); - xml = xml.replace("ram:InvoiceeTradeParty", "ram:InvoiceeCITradeParty"); - xml = xml.replace("ram:CategoryTradeTax", "ram:CategoryCITradeTax"); - xml = xml.replace("ram:SpecifiedTaxRegistration", "ram:SpecifiedCITaxRegistration"); - xml = xml.replace("ram:PostalTradeAddress", "ram:PostalCITradeAddress"); - xml = xml.replace("ram:SpecifiedTradePaymentTerms", "ram:SpecifiedCITradePaymentTerms"); - xml = xml.replace("ram:SpecifiedSupplyChainTradeAgreement", "ram:SpecifiedCIILSupplyChainTradeAgreement"); - xml = xml.replace("ram:GrossPriceProductTradePrice", "ram:GrossPriceProductCITradePrice"); - xml = xml.replace("ram:NetPriceProductTradePrice", "ram:NetPriceProductCITradePrice"); - xml = xml.replaceAll("(?s)\\", ""); - // remove manually for the time being: - // xml=xml.replaceAll("ram:TestIndicator>(.*?)/ram:TestIndicator>", ""); - // one ram:SpecifiedCIILTradeSettlementMonetarySummation will have to be - // ram:SpecifiedCIIHTradeSettlementMonetarySummation afterwards - - String summationClose = ""; - int posFirstSummation = xml.indexOf(summationClose) + summationClose.length(); - // if ram:SpecifiedTradeSettlementMonetarySummation were not found indexOf would - // return -1, therefore, - // to check if it - if (posFirstSummation > summationClose.length()) { - String xmlAfterFirstSummation = xml.substring(posFirstSummation); - String xmlBeforeIncludingFirstSummation = xml.substring(0, posFirstSummation); - // replace only once the header - - xmlBeforeIncludingFirstSummation = xmlBeforeIncludingFirstSummation.replace( - "ram:SpecifiedTradeSettlementMonetarySummation", - "ram:SpecifiedCIIHTradeSettlementMonetarySummation"); - // reconstruct the document now with a replaced first - // ram:SpecifiedTradeSettlementMonetarySummation to SpecifiedCIIH... - xml = xmlBeforeIncludingFirstSummation + xmlAfterFirstSummation; - + 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(); } - // replace the rest of the ram:SpecifiedTradeSettlementMonetarySummation with - // the line value SpecifiedCIIL... - xml = xml.replace("ram:SpecifiedTradeSettlementMonetarySummation", - "ram:SpecifiedCIILTradeSettlementMonetarySummation"); + String res=null; + try { + res=baos.toString("UTF-8"); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return res; + } - // the rest of the ram:SpecifiedTradeSettlementMonetarySummation should be in - // ram:ApplicableSupplyChainTradeSettlement - // xml=xml.replaceAll(Pattern.quote("ram:SpecifiedTradeSettlementMonetarySummation"), - // "ram:SpecifiedCIILTradeSettlementMonetarySummation"); - * - */ - return xml; + 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 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(cl.getResourceAsStream(resourcePath + href)); + } + } + + public static void applySchematronXsl(final InputStream xmlFile, + final OutputStream EN16931Outstream) throws TransformerException { + Transformer transformer = factory.newTransformer(new StreamSource(cl.getResourceAsStream(resourcePath+"COMFORTtoEN16931.xsl"))); + transformer.transform(new StreamSource(xmlFile), new StreamResult(EN16931Outstream)); } } diff --git a/src/main/java/org/mustangproject/toecount/Toecount.java b/src/main/java/org/mustangproject/toecount/Toecount.java index 1d90d2e3..10ff8500 100755 --- a/src/main/java/org/mustangproject/toecount/Toecount.java +++ b/src/main/java/org/mustangproject/toecount/Toecount.java @@ -281,9 +281,8 @@ public class Toecount { xmlName=getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false); outName=getFilenameFromUser("ZUGFeRD 2.0 XML target", "ZUGFeRD-2-invoice.xml", "xml", false, true); - String xml = new String(Files.readAllBytes(Paths.get(xmlName)), StandardCharsets.UTF_8); ZUGFeRDMigrator zmi=new ZUGFeRDMigrator(); - xml=zmi.migrateFromV1ToV2(xml); + String xml=zmi.migrateFromV1ToV2(xmlName); Files.write(Paths.get(outName), xml.getBytes()); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/resources/COMFORTtoEN16931.xsl b/src/main/resources/COMFORTtoEN16931.xsl new file mode 100644 index 00000000..1f6b81cd --- /dev/null +++ b/src/main/resources/COMFORTtoEN16931.xsl @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/schema/ZUGFeRD1p0.xsd b/src/main/resources/schema/ZUGFeRD1p0.xsd similarity index 100% rename from src/main/schema/ZUGFeRD1p0.xsd rename to src/main/resources/schema/ZUGFeRD1p0.xsd diff --git a/src/main/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_QualifiedDataType_12.xsd b/src/main/resources/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_QualifiedDataType_12.xsd similarity index 100% rename from src/main/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_QualifiedDataType_12.xsd rename to src/main/resources/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_QualifiedDataType_12.xsd diff --git a/src/main/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_ReusableAggregateBusinessInformationEntity_12.xsd b/src/main/resources/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_ReusableAggregateBusinessInformationEntity_12.xsd similarity index 100% rename from src/main/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_ReusableAggregateBusinessInformationEntity_12.xsd rename to src/main/resources/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_ReusableAggregateBusinessInformationEntity_12.xsd diff --git a/src/main/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_15.xsd b/src/main/resources/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_15.xsd similarity index 100% rename from src/main/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_15.xsd rename to src/main/resources/schema/ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_15.xsd