UBL XML Generator: Keep the Draft Separate From Validation

An invoice can show 24.00 USD while its XML lacks the currency attribute. Keep source fields and validation stages separate so a readable draft does not become an unsupported acceptance claim.

Generate fictional invoice text with namespace-qualified paths and escaped source text. Missing date holds generation; a deliberate failing copy removes only the payable currency attribute.

UBL XML Generator: Keep the Draft Separate From Validation
UBL XML Generator: Keep the Draft Separate From Validation
Open the full example ↗

Use a fictional base UBL 2.1 fixture

This original exercise fixes a small set of values:

Source field Authored value
Invoice ID INV-DEMO-136
Issue date 2026-10-14
Supplier name Cedar Practice
Customer name Workshop Practice
Line ID 1
Item description Training packet
Line extension amount 24.00 USD
Payable amount 24.00 USD

The names, invoice, line, and amounts are fictional. The exercise supplies totals rather than calculating taxes, prices, discounts, or legal obligations. It does not describe a payment or a submitted invoice.

Select base UBL 2.1 for this fixture. The Invoice namespace identifies the UBL document vocabulary; keep the selected release recorded separately. Do not treat a namespace suffix as the entire version/profile record.

OASIS's UBL 2.1 construction discussion demonstrates namespace-qualified invoice fields and model order. Its Invoice model identifies required date, parties, monetary total, and line structure. We use the native model with our own source values. UBL 2.1 specification, Invoice model

Keep each source field tied to its XML path

The supplier name belongs under AccountingSupplierParty / Party / PartyName / Name. The customer uses the corresponding AccountingCustomerParty path.

PayableAmount belongs under LegalMonetaryTotal. The line's LineExtensionAmount is a different value in a different location, even though both happen to be 24.00 USD in this fixture. Preserve the supplied decimal text and currency attributes.

This XML draft preserves the fixture's element order and source values; it has not been validated.

<?xml version="1.0" encoding="UTF-8"?>
<Invoice
  xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
  xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
  xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
  <cbc:ID>INV-DEMO-136</cbc:ID>
  <cbc:IssueDate>2026-10-14</cbc:IssueDate>
  <cac:AccountingSupplierParty>
    <cac:Party>
      <cac:PartyName>
        <cbc:Name>Cedar Practice</cbc:Name>
      </cac:PartyName>
    </cac:Party>
  </cac:AccountingSupplierParty>
  <cac:AccountingCustomerParty>
    <cac:Party>
      <cac:PartyName>
        <cbc:Name>Workshop Practice</cbc:Name>
      </cac:PartyName>
    </cac:Party>
  </cac:AccountingCustomerParty>
  <cac:LegalMonetaryTotal>
    <cbc:PayableAmount currencyID="USD">24.00</cbc:PayableAmount>
  </cac:LegalMonetaryTotal>
  <cac:InvoiceLine>
    <cbc:ID>1</cbc:ID>
    <cbc:LineExtensionAmount currencyID="USD">24.00</cbc:LineExtensionAmount>
    <cac:Item>
      <cbc:Description>Training packet</cbc:Description>
    </cac:Item>
  </cac:InvoiceLine>
</Invoice>

Keep the intended element order in the source mapping. The draft's amounts do not establish a unit quantity, unit price, tax treatment, or receiver acceptance. Those missing facts must not be inferred from the equal totals.

Check ordinary text through serialization and parsing

For source revision S2, change only the description to the ordinary text “Training packet & cards.”

The relevant expected XML fragment is <cbc:Description>Training packet &amp; cards</cbc:Description>. After an actual parse, the description's text value should be “Training packet & cards.” Serialized markup and parsed text are separate representations.

Keep missing-input and invalid-output cases different

In S3, remove IssueDate from the input record. The required-source check should hold generation and name that missing field. Do not invent today's date or retain an old date invisibly.

Label the earlier S1 or S2 output as belonging to its earlier source revision. It cannot become a current ready draft merely because it is still visible.

In S4, remove only the PayableAmount currency attribute to create a failing test copy. Do not repair it by assuming USD from the other amount. The source-to-output discrepancy is the point of the check. Preserve it as a clearly labeled failing test copy rather than replacing the maintained draft.

Give each validation stage its own evidence

Use a ledger with separate rows:

Stage What to record Current fixture status
Generation Input/output revision and bytes; serializer/version Not run
XML parse Processor/version; actual result; extracted values Not run
UBL XSD Exact schema release/artifacts; validator; result Not run
Code lists Exact configuration and checker; result Not run
Receiving profile Named receiver/profile/version and requirements [TO CONFIRM]

UBL 2.1's non-normative validation appendix describes schema structure/vocabulary checks separately from code-list verification. A schema result does not automatically establish every later requirement. UBL two-phase validation discussion

Keep test diagnostics, source/output fingerprints, and timestamps associated with the exact input and XML artifact tested. When a source field changes, invalidate that artifact's claim to represent the new source and schedule the relevant checks again.

Do not turn these rows into one automatic green “valid invoice” badge. The exercise has no confirmed receiving profile, network delivery, signature, payment, or national compliance review.

Make the audit readable without replacing XML

The XML draft is the native deliverable. An optional HTML view can explain source fields, qualified paths, output, and validation status side by side. It is a reading aid, not a substitute format for a recipient that requires XML.

Try the worked example

Generate the default, then enter “Training packet & cards.” The XML contains & while the source remains ordinary text. Remove the date to hold generation. Restore it and create the labeled missing-currency copy for a native schema check. Parsing and receiver acceptance are separate checks.

This generates draft XML text locally; it does not validate XSD/code lists/profile, sign, submit, pay, or establish legal compliance.

Recreate this example

Build one complete self-contained HTML page for this task: generate the original fictional UBL 2.1 Invoice draft text and expose source/attribute failures.

Use these exact original practice data and worked expectations: INV-DEMO-136; date 2026-10-14; supplier Cedar Practice; customer Workshop Practice; line 1, Training packet; LineExtensionAmount 24.00 USD; PayableAmount 24.00 USD. UBL 2.1 namespace URIs: default urn:oasis:names:specification:ubl:schema:xsd:Invoice-2; cac urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2; cbc urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2. No inferred tax or price.

Implement the following useful local interactions: Date/description fields; Generate and missing-currency test-copy buttons. Preserve 24.00 decimal strings, escape ordinary XML text once, hold missing/invalid date, clear stale XML, retain line currency in the failing copy. Keep the normal draft and negative test in two labeled output panes; input edits clear both. Validation stages stay unverified. Preserve the supplied source text and distinguish an uncomputed state, a successful local result, and an invalid or incomplete input. Update output only from the current input snapshot. An input edit must retire stale feedback until the reader runs the relevant action again. Do not silently invent missing values or replace a failing case with a success.

Design the page as a compact source-and-result developer workbench with readable code, labeled inputs, and a separate explanation area. Put a compact task heading, actual sample data, the main result, and usable controls early enough to be useful on a narrow screen. Use readable text of at least 16px, generous paragraph spacing, strong contrast, native labels, accessible buttons, and visible keyboard focus. Stack long records at 360px and wrap code without page-level horizontal overflow.

Use type=button and explicit querySelector-based click handlers rather than relying on form submission. If Enter is useful, handle it only on the relevant input and ignore isComposing. Keep effects within this open page; no remote dependencies, network calls, persistence, fake downloads, or automated sending. This generates draft XML text locally; it does not validate XSD/code lists/profile, sign, submit, pay, or establish legal compliance. Place worked explanations beside their data and identify teacher or synthetic examples clearly. Output only the complete HTML document, with inline styles and script and LF line endings.

Review the bounded UBL 2.1 XML draft generator in NOS

Keep the native XML and run the receiver’s actual checks before use. Keep the mapping in NOS beside the XML when a reviewer checks the supplier, customer, and payable paths; revise eligible static field explanations in visual editing mode when a path is unclear.

Keep reading