Electronic Commerce Modeling Language (ECML)
Wie zich wil storten op het bouwen van een webwinkel, een bestelsysteem of een andere vorm van e-commerce, hoeft daarvoor dankzij PHP en MySQL niet opnieuw het wiel uit te vinden. Je kunt bijvoorbeeld kant-en-klare oplossingen gebruiken zoals Magento (www.magentocommerce.com) en osCommerce (www.oscommerce.com). Minder bekend onder gebruikers van PHP en MySQL is dat er voor e-commerce al bijna tien jaar een aparte internetstandaard bestaat: Electronic Commerce Modeling Language of afgekort ECML.
Voor vooral het dataverkeer bij e-commerce bestaat sinds oktober 1999 een internetstandaard die nog nauwelijks bekend is: Electronic Commerce Modeling Language (ECML). Deze speciale internetstandaard voor e-commerce is vooral belangrijk omdat erin is bepaald welke naam u moet gebruiken voor variabelen. Als samenwerkende webapplicaties allemaal dezelfde variabelennamen accepteren, maakt dat online verkooptransacties veel gemakkelijker. Daarnaast is in ECML vastgelegd welke vorm bepaalde data moeten hebben en kent ECML een apart XML-structuur voor alle data.
Electronic Data Interchange (EDI) via HTML of XHTML
Als internettaal kan ECML worden gebruikt voor het uitwisselen van onder meer klantgegevens, adresgegevens en creditcardgegevens voor transacties met bijvoorbeeld vervoersbedrijven, banken, creditcardmaatschappijen en payment service providers (PSP’s). De gegevens die je vastlegt met PHP-applicaties of opslaat in MySQL-databases, worden dankzij ECML compatibel met systemen van andere bedrijven in het verkoopproces. Tenminste, dat is de bedoeling, want ECML wordt nog weinig gebruikt.
Meer praktisch is ECML vooral belangrijk voor het ontwerpen van formulieren in HTML en Extensible HTML (XHTML). In ECML is namelijk ook vastgelegd welke veldnamen je moet gebruiken in het HTML-element <input name="..." />. Voor de gebruikersverificatie kent ECML bijvoorbeeld de twee veldnamen Ecom_User_ID voor de gebruikersnaam en Ecom_User_Password voor het bijbehorende wachtwoord. In een formulier voor het aanmaken van een gebruikersaccount en later in een formulier voor het inloggen kun je dan de volgende XHTML-code gebruiken:
<form action="..." method="post">
...
<input type="text" name="Ecom_User_ID" />
...
<input type="password" name="Ecom_User_Password" />
...
<input type="hidden" name="Ecom_SchemaVersion" value="urn:ietf:params:ecml:v2.0" />
...
</form>
Deze ECML-oplossing zorgt ervoor dat de gebruikersnaam wordt verzonden met de variabelennaam Ecom_User_ID en het gebruikerswachtwoord met de variabelennaam Ecom_User_Password. Het verborgen formulierveld met de naam Ecom_SchemaVersion meldt daarnaast welke datastructuur wordt gebruikt voor deze ECML-gegevens; met de standaardwaarde urn:ietf:params:ecml:v2.0 geef je hier aan webapplicaties door dat er een uniform resource name (URN) wordt gebruikt van de Internet Engineering Task Force (IETF) voor ECML versie 2.0. Dit veld is vereist, vooral om webbrowsers te melden welke versie van ECML ze moeten gebruiken. Browsers kunnen deze melding vervolgens gebruiken om velden alvast te vullen met bijvoorbeeld AutoComplete ofwel AutoAanvullen.
Velden in ECMLv2
De tweede versie ECMLv2 uit juni 2005 (RFC 4112) kent de velden in de tabel aan het einde van dit artikel. De kolom ‘Min.’ noemt de aanbevolen minimumlengte voor elk veld. Alle velden worden uitgebreid toegelicht met noten in RFC 4112 op bijvoorbeeld http://tools.ietf.org/html/rfc4112, http://www.faqs.org/rfcs/rfc4112.html of http://www.rfc-editor.org/rfc/rfc4112.txt.
Merk op dat ECML drie soorten adressen kent: een bezorgadres met het prefix Ecom_ShipTo, een factuuradres met het prefix Ecom_BillTo en een derde adres met het prefix Ecom_ReceiptTo voor bijvoorbeeld een orderbevestiging of kopie van een factuur.
De velden met het prefix Ecom_Payment_Card zijn vooral bedoeld voor creditcards, de velden met Ecom_Loyalty_Card voor klantenkaarten of spaarkaarten en de velden met Ecom_User en Ecom_UserData voor gebruikersaccounts.
Beperkingen van ECML
Houd rekening met de volgende drie beperkingen van ECML. Als je deze internetstandaard wilt gebruiken, zul je enkele velden moeten verwijderen of aanpassen. Daarnaast kan het toevoegen van velden voor bepaalde applicaties zeker geen kwaad.
Verenigde Staten en Amerikaans Engels
Als taal leunt ECML erg op de situatie in de Verenigde Staten en het Amerikaanse Engels. Daardoor is ECML soms minder geschikt voor Europese of Nederlandstalige applicaties.
Een voorbeeld zijn de velden Ecom_ShipTo_Postal_StateProv en Ecom_BillTo_Postal_StateProv. Deze velden zijn bedoeld voor de afkorting van twee letters van een Amerikaanse staat in het bezorgadres (alle velden met het prefix Ecom_ShipTo) en het factuuradres (alles met Ecom_BillTo). In Nederland en België hebben die velden geen betekenis, omdat wij voldoende hebben aan de postcode in Ecom_ShipTo_Postal_PostalCode of Ecom_BillTo_Postal_PostalCode en de plaatsnaam in Ecom_ShipTo_Postal_City of Ecom_BillTo_Postal_City. Je kunt Ecom_ShipTo_Postal_StateProv gebruiken voor een provincie, maar dan wordt het dubbel redundant (overbodig): voor adressen is geen provincie nodig en de provincie is direct af te leiden uit de postcode.
Velden voor een staat of provincie kun je nog weglaten, maar dat geldt helaas niet voor de naam van een klant. Daarvoor gebruikt ECML een oplossing die vaak tot lokalisatieproblemen leidt — en tot usabilityfouten die je vaak aantreft in Nederlandstalige software van Microsoft. Voor namen wordt de typisch Amerikaanse vorm met drie velden gebruikt, bijvoorbeeld Ecom_ShipTo_Postal_Name_First, Ecom_ShipTo_Postal_Name_Middle plus Ecom_ShipTo_Postal_Name_Last. Deze typisch Amerikaanse opzet leidt vaak tot vergelijkbare complicaties, niet alleen in e-commerce maar ook in customer relationship management (CRM).
Wij kennen bijvoorbeeld een duidelijk verschil tussen voornamen en roepnamen. Johannes en Petrus worden Jan of Johan en Piet of Peter. ECML kent dat onderscheid niet, waardoor het veld Ecom_ShipTo_Postal_Name_First slecht bruikbaar wordt. Dat leidt tot dataverlies. Sla je bijvoorbeeld de roepnaam Jan op, dan is niet duidelijk wat de voornaam van de klant is: het kan kortweg Jan zijn, maar ook Johannes. Sla je echter de officiële voornaam Johannes op, dan is niet duidelijk hoe de klant moet worden aangesproken: het kan Jan, Johan of misschien John zijn.
Gebrekkige standaardisatie
De internetstandaard ECML verwijst wel naar bestaande normen van bijvoorbeeld de International Organization for Standardization (ISO), maar past die vaak erg slecht toe. Voor landen in de velden in de velden Ecom_ShipTo_Postal_CountryCode, Ecom_BillTo_Postal_CountryCode en Ecom_ReceiptTo_Postal_CountryCode worden keurig de gestandaardiseerde ISO-landcodes gebruikt, zoals NL voor Nederland en BE voor België. De bedenkers van ECML zijn echter vergeten dat er vergelijkbare ISO-codes bestaan voor talen, zoals nl voor Nederlands, en voor Engels en fr voor Frans. Voor de taal van de gebruikersgegevens gebruikt ECML nu nog het veld Ecom_UserData_Language met een vereiste minimumlengte van dertig karakters. Dat is niet alleen zonde van de opslagruimte. Het leidt ook veel eerder tot fouten, zoals de vervuilde data Nederlands, Dutch, nl-NL en nl voor één taal.
Het opslaan van een taal in een lang tekstveld van minimaal dertig karakters is onhandig, maar dat kunnen we nog vergeven door het een ‘keuze’ te noemen. Andere oplossingen in ECML zijn echt fout. Voor het geslacht verwijst ECML bijvoorbeeld naar de norm ISO/IEC 5218, Information technology -- Codes for the representation of human sexes. Daarvan wordt de sterk verouderde versie gebruikt met de drie letters M van male (mannelijk), F van female (vrouwelijk) en U van unknown (onbekend). Deze actuele versie van ISO-norm 5218 gebruikt echter niet meer drie letters, maar vier integers.
| Code | Engels | Nederlands | Frans |
|---|---|---|---|
| 0 | Not known | Onbekend | Inconnu |
| 1 | Male | Mannelijk | Masculin |
| 2 | Female | Vrouwelijk | Féminin |
| 9 | Not applicable | Niet van toepassing | Sans objet |
De vernieuwde ISO-norm is om zeker drie redenen beter:
- Een kleine integer kost minder opslagruimte dan een karakter. In MySQL kun je hiervoor het datatype TINYINT(1) UNSIGNED gebruiken in plaats van CHAR(1) of VARCHAR(1).
- Getallen maken een oplossing onafhankelijk van de gebruikte taal. De verouderde
Uvan unknown heeft alleen een betekenis in het Engels. Het verkleint ook de kans op fouten, want sommige Nederlandse webdevelopers zullen geneigd zijn eenVin te vullen waar het eenFmoest zijn. - Nog belangrijker voor e-commerce is de toevoeging van de vierde toestand
9voor Niet van toepassing. Als de klant namelijk geen man of vrouw is maar een bedrijf of andere organisatie, is een aparte code geen overbodige luxe.
Praktische implementatie
Sommige oplossingen in ECML zijn niet effectief of werken praktisch gewoon onhandig. In Nederland kan een bestelling worden bezorgd met slechts drie gegevens: de postcode, het huisnummer en een eventuele huisnummertoevoeging (bijvoorbeeld de letter A in huisnummer 123-A). Pakketdiensten die in Nederland opereren. zoals TNT Post (www.tntpost.nl) en DHL van Deutsche Post (www.dhl.nl), gebruiken meestal deze drie velden voor het invoeren van adressen in hun systemen. In ECML worden echter velden gebruikt zoals Ecom_ShipTo_Postal_Street_Line1 en Ecom_ShipTo_Postal_PostalCode. Er is wel een apart veld voor de postcode, maar het huisnummer en de huisnummertoevoeging staan samen met de straatnaam in één veld voor één adresregel. En drie verschillende gegevens opslaan in één veld werkt natuurlijk niet goed als je de bezorging fatsoenlijk wilt automatiseren.
Velden en veldnamen in ECMLv2
| Veld | Naam | Min. |
|---|---|---|
| ship to title | Ecom_ShipTo_Postal_Name_Prefix | 4 |
| ship to first name | Ecom_ShipTo_Postal_Name_First | 15 |
| ship to middle name | Ecom_ShipTo_Postal_Name_Middle | 15 |
| ship to last name | Ecom_ShipTo_Postal_Name_Last | 15 |
| ship to name suffix | Ecom_ShipTo_Postal_Name_Suffix | 4 |
| ship to company name | Ecom_ShipTo_Postal_Company | 20 |
| ship to street line1 | Ecom_ShipTo_Postal_Street_Line1 | 20 |
| ship to street line2 | Ecom_ShipTo_Postal_Street_Line2 | 20 |
| ship to street line3 | Ecom_ShipTo_Postal_Street_Line3 | 20 |
| ship to city | Ecom_ShipTo_Postal_City | 22 |
| ship to state/province | Ecom_ShipTo_Postal_StateProv | 2 |
| ship to zip/postal code | Ecom_ShipTo_Postal_PostalCode | 14 |
| ship to country | Ecom_ShipTo_Postal_CountryCode | 2 |
| ship to phone | Ecom_ShipTo_Telecom_Phone_Number | 10 |
| ship to email | Ecom_ShipTo_Online_Email | 40 |
| bill to title | Ecom_BillTo_Postal_Name_Prefix | 4 |
| bill to first name | Ecom_BillTo_Postal_Name_First | 15 |
| bill to middle name | Ecom_BillTo_Postal_Name_Middle | 15 |
| bill to last name | Ecom_BillTo_Postal_Name_Last | 15 |
| bill to name suffix | Ecom_BillTo_Postal_Name_Suffix | 4 |
| bill to company name | Ecom_BillTo_Postal_Company | 20 |
| bill to street line1 | Ecom_BillTo_Postal_Street_Line1 | 20 |
| bill to street line2 | Ecom_BillTo_Postal_Street_Line2 | 20 |
| bill to street line3 | Ecom_BillTo_Postal_Street_Line3 | 20 |
| bill to city | Ecom_BillTo_Postal_City | 22 |
| bill to state/province | Ecom_BillTo_Postal_StateProv | 2 |
| bill to zip/postal code | Ecom_BillTo_Postal_PostalCode | 14 |
| bill to country | Ecom_BillTo_Postal_CountryCode | 2 |
| bill to phone | Ecom_BillTo_Telecom_Phone_Number | 10 |
| bill to email | Ecom_BillTo_Online_Email | 40 |
| receipt to title | Ecom_ReceiptTo_Postal_Name_Prefix | 4 |
| receipt to first name | Ecom_ReceiptTo_Postal_Name_First | 15 |
| receipt to middle name | Ecom_ReceiptTo_Postal_Name_Middle | 15 |
| receipt to last name | Ecom_ReceiptTo_Postal_Name_Last | 15 |
| receipt to name suffix | Ecom_ReceiptTo_Postal_Name_Suffix | 4 |
| receipt to company name | Ecom_ReceiptTo_Postal_Company | 20 |
| receipt to street line1 | Ecom_ReceiptTo_Postal_Street_Line1 | 20 |
| receipt to street line2 | Ecom_ReceiptTo_Postal_Street_Line2 | 20 |
| receipt to street line3 | Ecom_ReceiptTo_Postal_Street_Line3 | 20 |
| receipt to city | Ecom_ReceiptTo_Postal_City | 22 |
| receipt to state/province | Ecom_ReceiptTo_Postal_StateProv | 2 |
| receipt to postal code | Ecom_ReceiptTo_Postal_PostalCode | 14 |
| receipt to country | Ecom_ReceiptTo_Postal_CountryCode | 2 |
| receipt to phone | Ecom_ReceiptTo_Telecom_Phone_Number | 10 |
| receipt to email | Ecom_ReceiptTo_Online_Email | 40 |
| name on card | Ecom_Payment_Card_Name | 30 |
| card type | Ecom_Payment_Card_Type | 4 |
| card number | Ecom_Payment_Card_Number | 19 |
| card verification value | Ecom_Payment_Card_Verification | 4 |
| card issuer number | Ecom_Payment_Card_IssueNumber | 2 |
| card expire date day | Ecom_Payment_Card_ExpDate_Day | 2 |
| card expire date month | Ecom_Payment_Card_ExpDate_Month | 2 |
| card expire date year | Ecom_Payment_Card_ExpDate_Year | 4 |
| card valid date day | Ecom_Payment_Card_ValidFrom_Day | 2 |
| card valid date month | Ecom_Payment_Card_ValidFrom_Month | 2 |
| card valid date year | Ecom_Payment_Card_ValidFrom_Year | 4 |
| card protocols | Ecom_Payment_Card_Protocol | 20 |
| loyalty card name | Ecom_Loyalty_Card_Name | 30 |
| loyalty card type | Ecom_Loyalty_Card_Type | 20 |
| loyalty card number | Ecom_Loyalty_Card_Number | 40 |
| loyalty card verification | Ecom_Loyalty_Card_Verification | 4 |
| loyalty card expire day | Ecom_Loyalty_Card_ExpDate_Day | 2 |
| loyalty card expire month | Ecom_Loyalty_Card_ExpDate_Month | 2 |
| loyalty card expire year | Ecom_Loyalty_Card_ExpDate_Year | 2 |
| loyalty card valid day | Ecom_Loyalty_Card_ValidFrom_Day | 2 |
| loyalty card valid month | Ecom_Loyalty_Card_ValidFrom_Month | 2 |
| loyalty card valid year | Ecom_Loyalty_Card_ValidFrom_Year | 4 |
| consumer order ID | Ecom_ConsumerOrderID | 20 |
| user ID | Ecom_User_ID | 40 |
| user password | Ecom_User_Password | 20 |
| user certificate | Ecom_User_Certificate_URL | 128 |
| user data country | Ecom_UserData_Country | 2 |
| user data language | Ecom_UserData_Language | 30 |
| user data gender | Ecom_UserData_Gender | 1 |
| user data birth day | Ecom_UserData_BirthDate_Day | 2 |
| user data birth month | Ecom_UserData_BirthDate_Month | 2 |
| user data birth year | Ecom_UserData_BirthDate_Year | 4 |
| user data preferences | Ecom_UserData_Preferences | 60 |
| schema version | Ecom_SchemaVersion | 30 |
| wallet ID | Ecom_WalletID | 40 |
| wallet URL | Ecom_Wallet_Location | 128 |
| customer device ID | Ecom_Device_ID | 20 |
| customer device type | Ecom_Device_Type | 20 |
| end transaction flag | Ecom_TransactionComplete | - |
| merchant home domain | Ecom_Merchant | 128 |
| processor home domain | Ecom_Processor | 128 |
| transaction identifier | Ecom_Transaction_ID | 128 |
| transaction URL inquiry | Ecom_Transaction_Inquiry | 500 |
| transaction amount | Ecom_Transaction_Amount | 128 |
| transaction currency | Ecom_Transaction_CurrencyCode | 3 |
| transaction date | Ecom_Transaction_Date | 80 |
| transaction type | Ecom_Transaction_Type | 24 |
| transaction signature | Ecom_Transaction_Signature | 160 |
| end transaction flag | Ecom_TransactionComplete | - |
| merchant identifier | Ecom_Merchant_ID | 8 |
| merchant terminal | Ecom_Merchant_Terminal_ID | 8 |
| merchant terminal data | Ecom_Merchant_Terminal_Data | 128 |
| transaction process code | Ecom_Transaction_ProcessingCode | 6 |
| transaction reference | Ecom_Transaction_Reference_ID | 12 |
| transaction acquirer | Ecom_Transaction_Acquire_ID | 13 |
| transaction forward | Ecom_Transaction_Forward_ID | 13 |
| transaction trace | Ecom_Transaction_Trace_Audit | 6 |
| transaction effective date | Ecom_Transaction_Effective_Date | 4 |
| transaction CID | Ecom_Transaction_CID | 8 |
| transaction POS | Ecom_Transaction_POSCode | 12 |
| transaction private use | Ecom_Transaction_PrivateUseData | 166 |
| transaction response | Ecom_Transaction_ResponseData | 27 |
| transaction approval code | Ecom_Transaction_ApprovalCode | 12 |
| transaction retrieval code | Ecom_Transaction_RetrievalCode | 128 |
| transaction response action | Ecom_Transaction_ActionCode | 13 |
| transaction reason | Ecom_Transaction_ReasonCode | 4 |
| transaction AAV | Ecom_Transaction_AAV | 3 |
| transaction settlement date | Ecom_Transaction_Settle_Date | 4 |
| transaction capture date | Ecom_Transaction_Capture_Date | 4 |
| transaction Track 1 | Ecom_Transaction_Track1 | 39 |
| transaction Track 2 | Ecom_Transaction_Track2 | 39 |
