Reactiate improved migration feature, this time in the library

This commit is contained in:
Jochen Stärk
2020-10-29 17:26:04 +01:00
parent a21e33efdb
commit f47222ee58
7 changed files with 455 additions and 209 deletions

View File

@@ -7,6 +7,7 @@
- fluent setter api/pushprovider #40
- new xrechnung profile
- visualization? zugferdvisualizer?
- migration feature (XSLT upgrade of ZF1 to ZF2) has been improved and moved from the commandline into the library
- german bank account numbers can no longer be specified (dropped in favor of IBAN and BIC)
- factory for xrechnung #86
- moved to Maven central
@@ -17,7 +18,6 @@
- getSellerTradePartyAddress (PR #157 ) thanks to aberndt-hub
- switched from eclipse to IntelliJ
- added ph-schematron-maven-plugin so that xrechnung xslt can be generated
- removed migration feature (XSLT upgrade of ZF1)
- be able to recursively validate directories
- be able to ignore input pdf errors with -i
- be able to recursively scan directories using validateExpectValid/validateExpectInvalid
@@ -58,6 +58,9 @@ switch
- *from A3 does not seem tow ork see mustangreaderwriteredgetest:testedgeexport
- xmp errors may not show correctly in log
- confirm correct generation from pdf/a3 files zf2edgetest
- visualization tests
- migration tests
- migration documentation
- *correctiontest exports zf1+zf2?
- *USt 0% wird aus invoice-klasse noch nicht sauber abgefangen
- finalize invoiceimporter

View File

@@ -71,6 +71,10 @@ public class Main {
+ " [--profile <...>]: set ZUGFeRD profile\n"
+ " For ZUGFeRD v1: <B>ASIC, <C>OMFORT or EX<T>ENDED\n"
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, <X>Rechnung, EX<T>ENDED "
+ " upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input XML ZUGFeRD 1 file\n"
+ " [--out <filename>]: set output XML ZUGFeRD 2 file\n"
+ " validate validate XML or PDF file \n"
+ " [--no-notices]: refrain from reporting notices\n"
+ " [--logAppend=<text>]: text to be added to log line\n"
@@ -221,8 +225,35 @@ public class Main {
return selectedName;
}
private static void performUpgrade(String xmlName, String outName) throws IOException, TransformerException {
// /opt/local/bin/mvn clean compile assembly:single
// Get params from user if not already defined
if (xmlName == null) {
xmlName = getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false);
} else {
System.out.println("ZUGFeRD 1.0 XML source set to " + xmlName);
}
if (outName == null) {
outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "factur-x.xml", "xml", false, true);
} else {
System.out.println("ZUGFeRD 2 XML target to " + outName);
}
// Verify params
ensureFileExists(xmlName);
ensureFileNotExists(outName);
// All params are good! continue...
XMLUpgrader zmi = new XMLUpgrader();
String xml = zmi.migrateFromV1ToV2(xmlName);
Files.write(Paths.get(outName), xml.getBytes());
System.out.println("Written to " + outName);
}
/***
* the main function of the commandline tool...
* @param args
*/
public static void main(String[] args) {
try {
@@ -303,6 +334,9 @@ public class Main {
} else if ((action!=null)&&(action.equals("visualize"))) {
performVisualization(sourceName, outName);
optionsRecognized=true;
} else if ((action!=null)&&(action.equals("upgrade"))) {
performUpgrade(sourceName, outName);
optionsRecognized=true;
} else if ((action!=null)&&(action.equals("validate"))) {
optionsRecognized=performValidate(sourceName, noNotices!=null&&noNotices, parser.getOptionValue(logAppendOption));
} else if ((action!=null)&&(action.equals("validateExpectValid"))) {

View File

@@ -1,205 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:qdt="urn:un:unece:uncefact:data:Standard:QualifiedDataType:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"><!--
Migrated by Mustangproject XSLT
-->
<rsm:ExchangedDocumentContext>
<ram:TestIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:TestIndicator>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:ferd:CrossIndustryDocument:invoice:1p0:extended</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100">
<ram:ID>RE-20170509/505</ram:ID>
<ram:Name>RECHNUNG</ram:Name>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20170509</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100">
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Künstlerische Gestaltung (Stunde): Einer Beispielrechnung</ram:Name>
<ram:Description/>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount currencyID="EUR">160.0000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount currencyID="EUR">160.0000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="HUR">1.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount currencyID="EUR">160.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Luftballon: Bunt, ca. 500ml</ram:Name>
<ram:Description/>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount currencyID="EUR">0.7900</ram:ChargeAmount>
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount currencyID="EUR">0.7900</ram:ChargeAmount>
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">400.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount currencyID="EUR">316.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>3</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Heiße Luft pro Liter</ram:Name>
<ram:Description/>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount currencyID="EUR">0.1000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount currencyID="EUR">0.1000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="LTR">200.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount currencyID="EUR">20.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Bei Spiel GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>12345</ram:PostcodeCode>
<ram:LineOne>Ecke 12</ram:LineOne>
<ram:CityName>Stadthausen</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="FC">22/815/0815/4</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE136695976</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Theodor Est</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>88802</ram:PostcodeCode>
<ram:LineOne>Bahnstr. 42</ram:LineOne>
<ram:CityName>Spielkreis</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE999999999</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20170507</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:PaymentReference>RE-20170509/505</ram:PaymentReference>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>42</ram:TypeCode>
<ram:Information>Überweisung</ram:Information>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>DE88 2008 0000 0970 3757 00</ram:IBANID>
<ram:ProprietaryID>44421800</ram:ProprietaryID>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayeeSpecifiedCreditorFinancialInstitution>
<ram:BICID>COBADEFFXXX</ram:BICID>
<ram:GermanBankleitzahlID>41441604</ram:GermanBankleitzahlID>
<ram:Name>Commerzbank</ram:Name>
</ram:PayeeSpecifiedCreditorFinancialInstitution>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount currencyID="EUR">11.20</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount currencyID="EUR">160.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount currencyID="EUR">63.84</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount currencyID="EUR">336.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Zahlbar ohne Abzug bis zum 30.05.2017</ram:Description>
<ram:DueDateDateTime>
<udt:DateTimeString format="102">20170530</udt:DateTimeString>
</ram:DueDateDateTime>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount currencyID="EUR">496.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount currencyID="EUR">0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount currencyID="EUR">0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount currencyID="EUR">496.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">75.04</ram:TaxTotalAmount>
<ram:GrandTotalAmount currencyID="EUR">571.04</ram:GrandTotalAmount>
<ram:DuePayableAmount currencyID="EUR">571.04</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

View File

@@ -30,6 +30,7 @@ package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
import java.util.Date;
import org.mustangproject.FileAttachment;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
public interface IExportableTransaction {

View File

@@ -0,0 +1,68 @@
package org.mustangproject.ZUGFeRD;
import javax.xml.transform.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
/***
* Uses a XSLT transformation to upgrade
* from ZUGFeRD 1 to ZUGFeRD 2 (=Factur-X1 ˜= XRechnung)
* This is an external functionality of the software and not very complete, for
* internal operations (generation of ZF2) of course the ZF2PullProvider is used
*/
public class XMLUpgrader {
static final ClassLoader CLASS_LOADER = XMLUpgrader.class.getClassLoader();
private static final String RESOURCE_PATH = ""; //$NON-NLS-1$
private TransformerFactory mFactory = null;
private Templates mXsltTemplate = null;
public XMLUpgrader() {
mFactory = new net.sf.saxon.TransformerFactoryImpl();
//fact = TransformerFactory.newInstance();
mFactory.setURIResolver(new ClasspathResourceURIResolver());
}
/***
* Takes a filename of a ZF1 XML file and returns the string of ZF2 XML
* @param xmlFilename
* @return String the updated XML
* @throws FileNotFoundException
* @throws TransformerException
* @throws UnsupportedEncodingException
*/
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
*/
mXsltTemplate = mFactory.newTemplates(new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZF1ToZF2.xsl")));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
applySchematronXsl(new FileInputStream(xmlFilename), baos);
String res = null;
res = baos.toString("UTF-8");
return res;
}
protected 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));
}
}
}

View File

@@ -30,11 +30,13 @@ import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.mustangproject.FileAttachment;
import org.mustangproject.Invoice;
import org.mustangproject.XMLTools;
@@ -496,13 +498,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide
// Additional Documents of XRechnung (Rechnungsbegruendende Unterlagen - BG-24 XRechnung)
if (trans.getAdditionalReferencedDocuments() != null) {
for (FileAttachment f : trans.getAdditionalReferencedDocuments()) {
final String documentContent = Base64.encodeBase64String(f.getData());
// final String documentContent = Base64.encodeBase64String(f.getData());
xml = xml + " <ram:AdditionalReferencedDocument>\n"
+ " <ram:IssuerAssignedID>" + f.getFilename() + "</ram:IssuerAssignedID>\n"
+ " <ram:TypeCode>916</ram:TypeCode>\n"
+ " <ram:Name>" + f.getDescription() + "</ram:Name>\n"
+ " <ram:AttachmentBinaryObject mimeCode=\"" + f.getMimetype() + "\"\n"
+ " filename=\"" + f.getFilename() + ">" + documentContent + "\n"
// + " filename=\"" + f.getFilename() + ">" + documentContent + "\n"
+ " </ram:AdditionalReferencedDocument>\n";
}
}

View File

@@ -0,0 +1,343 @@
<!--
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.
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.
-->
<!--
This XSL transformation will attempt to migrate from ZF1 (which was a customized UN/CEFACT CII 2013b) to ZF2
(which is vanilla UN/CEFACT CII 2016b).
In general, some elements have been renamed and with many elements the sequence of the sub-elements is now defined
-->
<xsl:stylesheet version="2.0"
xpath-default-namespace="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
exclude-result-prefixes="qdt"
>
<!-- use saxon6 java -cp saxon.jar com.icl.saxon.StyleSheet -o target.xml
ZUGFeRD-invoice.xml v1to2.xsl see also http://www.lenzconsulting.com/namespaces-in-xslt/
extension-element-prefixes="exsl str datetime uw" -->
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
<xsl:template
name="search-and-replace"><!-- quelle: https://www.data2type.de/xml-xslt-xslfo/xslt/xslt-kochbuch/strings/text-ersetzen/ , replace does not work in MSXML... -->
<xsl:param name="input"/>
<xsl:param name="search-string"/>
<xsl:param name="replace-string"/>
<xsl:choose>
<!-- Feststellen, ob die Eingabe den Suchstring enthält -->
<xsl:when test="$search-string and contains($input,$search-string)">
<!-- Ist dies der Fall, dann Verkettung des Teilstrings vor dem Suchstring mit dem Ersatzstring und mit dem Ergebnis der rekursiven Anwendung dieses Templates mit dem verbleibenden Teilstring. -->
<xsl:value-of select="substring-before($input,$search-string)"/>
<xsl:value-of select="$replace-string"/>
<xsl:call-template name="search-and-replace">
<xsl:with-param name="input" select="substring-after($input,$search-string)"/>
<xsl:with-param name="search-string" select="$search-string"/>
<xsl:with-param name="replace-string" select="$replace-string"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- Keine weiteren Vorkommen des Suchstrings, daher einfach Rückgabe des aktuellen Eingabestrings -->
<xsl:value-of select="$input"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- copy elements and all attributes but remove namespaces start
Will otherwise add sth like xmlns:rsm="urn:ferd:CrossIndustryDocument:invoice:1p0" on elements.
src: https://stackoverflow.com/questions/12465002/remove-namespace-declaration-from-xslt-stylesheet-with-xslt
This only seems to work in saxon, in xalan namespaces are still created-->
<!-- Copy elements -->
<xsl:template match="*" priority="-1">
<xsl:element name="{name()}">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
<!-- Copy all other nodes -->
<xsl:template match="node()|@*" priority="-2">
<xsl:copy/>
</xsl:template>
<!-- copy elements and all attributes but remove namespaces end -->
<xsl:template match="//*[local-name() = 'CrossIndustryDocument']">
<!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" -->
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:qdt="urn:un:unece:uncefact:data:Standard:QualifiedDataType:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<xsl:apply-templates select="*"/>
</rsm:CrossIndustryInvoice>
</xsl:template>
<!-- xsl:template match="//*[local-name() = 'HeaderExchangedDocument']">
<xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> -->
<!-- element remode -->
<xsl:template match="//*[local-name() = 'TestIndicator']">
<!-- Testindicator element has been removed -->
</xsl:template>
<!-- element rename -->
<xsl:template match="//*[local-name() = 'SpecifiedExchangedDocumentContext']">
<xsl:element name="rsm:ExchangedDocumentContext">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="//*[local-name() = 'GuidelineSpecifiedDocumentContextParameter']/*[local-name() = 'ID']">
<!--
We need to replace the old ZF1 guideline IDs (=profiles) with the new ones:
''' urn:ferd:CrossIndustryDocument:invoice:1p0:basic -> urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic
''' urn:ferd:CrossIndustryDocument:invoice:1p0:comfort -> urn:cen.eu:en16931:2017
''' urn:ferd:CrossIndustryDocument:invoice:1p0:extended -> urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
-->
<ram:ID>
<xsl:variable name="correctedBasic">
<xsl:call-template name="search-and-replace">
<xsl:with-param name="input" select="./text()"/>
<xsl:with-param name="search-string" select="'urn:ferd:CrossIndustryDocument:invoice:1p0:basic'"/>
<xsl:with-param name="replace-string"
select="'urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="alsoCorrectedComfort">
<xsl:call-template name="search-and-replace">
<xsl:with-param name="input" select="$correctedBasic"/>
<xsl:with-param name="search-string" select="'urn:ferd:CrossIndustryDocument:invoice:1p0:comfort'"/>
<xsl:with-param name="replace-string" select="'urn:cen.eu:en16931:2017'"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="search-and-replace">
<xsl:with-param name="input" select="$alsoCorrectedComfort"/>
<xsl:with-param name="search-string" select="'urn:ferd:CrossIndustryDocument:invoice:1p0:extended'"/>
<xsl:with-param name="replace-string"
select="'urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended'"/>
</xsl:call-template>
</ram:ID>
</xsl:template>
<xsl:template match="//*[local-name() = 'HeaderExchangedDocument']">
<rsm:ExchangedDocument>
<xsl:apply-templates select="@*|node()"/>
</rsm:ExchangedDocument>
</xsl:template>
<xsl:template match="//*[local-name() = 'ApplicablePercent']">
<ram:RateApplicablePercent>
<xsl:apply-templates select="@*|node()"/>
</ram:RateApplicablePercent>
</xsl:template>
<xsl:template match="//*[local-name() = 'SpecifiedSupplyChainTradeDelivery']">
<ram:SpecifiedLineTradeDelivery>
<xsl:apply-templates select="@*|node()"/>
</ram:SpecifiedLineTradeDelivery>
</xsl:template>
<xsl:template match="//*[local-name() = 'SpecifiedLineTradeAgreement']">
<ram:AssociatedDocumentLineDocument>
<xsl:apply-templates select="@*|node()"/>
</ram:AssociatedDocumentLineDocument>
</xsl:template>
<xsl:template
match="//*[local-name() = 'SpecifiedSupplyChainTradeAgreement']">
<ram:SpecifiedLineTradeAgreement>
<xsl:apply-templates select="@*|node()"/>
</ram:SpecifiedLineTradeAgreement>
</xsl:template>
<xsl:template
match="//*[local-name() = 'SpecifiedSupplyChainTradeSettlement']">
<ram:SpecifiedLineTradeSettlement>
<xsl:apply-templates select="@*|node()"/>
</ram:SpecifiedLineTradeSettlement>
</xsl:template>
<!-- SpecifiedTradeSettlementMonetarySummation -> SpecifiedTradeSettlementLineMonetarySummation
unterhalb SpecifiedLineTradeSettlement -> SpecifiedTradeSettlementHeaderMonetarySummation
unterhalb ApplicableHeaderTradeSettlement -->
<xsl:template
match="//*[local-name()='SpecifiedSupplyChainTradeSettlement']/*[local-name()='SpecifiedTradeSettlementMonetarySummation']">
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<xsl:apply-templates select="@*|node()"/>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</xsl:template>
<!-- ApplicableSupplyChainTradeSettlement -->
<xsl:template
match="//*[local-name() = 'ApplicableSupplyChainTradeSettlement']/*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']">
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<xsl:apply-templates select="@*|node()"/>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</xsl:template>
<xsl:template
match="//*[local-name() = 'ApplicableSupplyChainTradeAgreement']">
<ram:ApplicableHeaderTradeAgreement>
<xsl:apply-templates select="@*|node()"/>
</ram:ApplicableHeaderTradeAgreement>
</xsl:template>
<xsl:template
match="//*[local-name() = 'ApplicableSupplyChainTradeDelivery']">
<ram:ApplicableHeaderTradeDelivery>
<xsl:apply-templates select="@*|node()"/>
</ram:ApplicableHeaderTradeDelivery>
</xsl:template>
<xsl:template
match="//*[local-name() = 'ApplicableSupplyChainTradeSettlement']">
<ram:ApplicableHeaderTradeSettlement>
<xsl:apply-templates select="@*|node()"/>
</ram:ApplicableHeaderTradeSettlement>
</xsl:template>
<xsl:template
match="//*[local-name() = 'SpecifiedTradeAccountingAccount']">
<ram:ReceivableSpecifiedTradeAccountingAccount>
<xsl:apply-templates select="@*|node()"/>
</ram:ReceivableSpecifiedTradeAccountingAccount>
</xsl:template>
<!-- rename hierarchical -->
<xsl:template
match="//*[local-name() = 'BuyerOrderReferencedDocument' or local-name() = 'DeliveryNoteReferencedDocument' or local-name() = 'AdditionalReferencedDocument' or local-name() = 'ContractReferencedDocument']/*[local-name() = 'ID']">
<ram:IssuerAssignedID>
<xsl:apply-templates select="@*|node()"/>
</ram:IssuerAssignedID>
</xsl:template>
<xsl:template
match="//*[local-name() = 'ContractReferencedDocument']/*[local-name() = 'TypeCode']">
<ram:ReferenceTypeCode>
<xsl:apply-templates select="@*|node()"/>
</ram:ReferenceTypeCode>
</xsl:template>
<!-- rename and add -->
<xsl:template match="//*[local-name() != 'HeaderExchangedDocument']/*[local-name() = 'IssueDateTime']">
<ram:FormattedIssueDateTime>
<qdt:DateTimeString>
<xsl:apply-templates select="@*|node()"/>
</qdt:DateTimeString>
</ram:FormattedIssueDateTime>
</xsl:template>
<!-- rename and reorder -->
<xsl:template
match="//*[local-name() = 'SpecifiedSupplyChainTradeTransaction']">
<rsm:SupplyChainTradeTransaction><!-- surplus namespaces -->
<xsl:apply-templates
select="./*[local-name() = 'IncludedSupplyChainTradeLineItem']"/>
<!-- now copy any other children that we haven't explicitly reordered;
again, possibly this is not what you want -->
<xsl:apply-templates
select="./*[not(local-name() = 'IncludedSupplyChainTradeLineItem')]"/>
</rsm:SupplyChainTradeTransaction>
</xsl:template>
<xsl:template
match="//*[local-name() = 'BuyerOrderReferencedDocument' or local-name() = 'DeliveryNoteReferencedDocument' or local-name() = 'AdditionalReferencedDocument' or local-name() = 'ContractReferencedDocument']">
<xsl:element name="{name()}">
<xsl:apply-templates
select="./*[local-name() = 'ID']"/>
<xsl:apply-templates
select="./*[local-name() = 'TypeCode']"/>
<xsl:apply-templates
select="./*[not(local-name() = 'ID' or local-name() = 'TypeCode')]"/>
</xsl:element>
</xsl:template>
<!-- innerhalb IncludedSupplyChainTradeLineItem zuerst AssociatedDocumentLineDocument
dann SpecifiedTradeProduct -->
<xsl:template match="//*[local-name() = 'IncludedSupplyChainTradeLineItem']">
<ram:IncludedSupplyChainTradeLineItem>
<xsl:apply-templates
select="./*[local-name() = 'AssociatedDocumentLineDocument']"/>
<xsl:apply-templates select="./*[local-name() = 'SpecifiedTradeProduct']"/>
<!-- now copy any other children that we haven't explicitly reordered;
again, possibly this is not what you want -->
<xsl:apply-templates
select="./*[not(local-name() = 'AssociatedDocumentLineDocument' or local-name() = 'SpecifiedTradeProduct')]"/>
</ram:IncludedSupplyChainTradeLineItem>
</xsl:template>
<xsl:template
match="//*[local-name() = 'SpecifiedLineTradeSettlement']">
<ram:SpecifiedLineTradeSettlement>
<xsl:apply-templates
select="./*[not(local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation' or local-name() = 'SpecifiedTradeSettlementLineMonetarySummation' or local-name() = 'SpecifiedTradeAccountingAccount')]"/>
<xsl:apply-templates
select="./*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']"/>
<xsl:apply-templates
select="./*[local-name() = 'SpecifiedTradeSettlementLineMonetarySummation']"/>
<xsl:apply-templates
select="./*[local-name() = 'SpecifiedTradeAccountingAccount']"/>
</ram:SpecifiedLineTradeSettlement>
</xsl:template>
<xsl:template
match="//*[local-name() = 'ApplicableHeaderTradeSettlement' or local-name() = 'SpecifiedLineTradeSettlement']">
<xsl:element name="{name()}">
<xsl:apply-templates
select="./*[not(local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation' or local-name() = 'SpecifiedTradeSettlementMonetarySummation' or local-name() = 'SpecifiedTradeAccountingAccount')]"/>
<!-- xsl:apply-templates
select="./*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']" /-->
<xsl:apply-templates
select="./*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']"/>
<xsl:apply-templates
select="./*[local-name() = 'SpecifiedTradeAccountingAccount']"/>
</xsl:element>
</xsl:template>
<!-- unterhalb von SupplyChainTradeTransaction muss zuerst die IncludedSupplyChainTradeLineItem
kommen -->
<!-- rest -->
<!-- this is the identity transform: it copies everything that isn't matched
by a more specific template -->
</xsl:stylesheet>