cxpath module
The xml.cxpath module
The xml.cxpath module provides XPath XML querying capabilities using the cxpath library. It’s useful for parsing XML files like ZUGFeRD invoices.
local cxpath = require("xml.cxpath")Module functions
| Name | Parameters | Returns | Description |
|---|---|---|---|
cxpath.open() |
filename (string) | Context | Open and parse an XML file |
Context
Represents an XPath context for querying XML.
local ctx = cxpath.open("document.xml")Attributes
| Name | R | Type | Description |
|---|---|---|---|
string |
R | string | String value of current node |
Methods
| Name | Parameters | Returns | Description |
|---|---|---|---|
set_namespace() |
prefix, uri | self | Register a namespace prefix |
eval() |
xpath (string) | Context | Evaluate XPath expression |
each() |
xpath (string) | iterator | Iterate over matching nodes |
root() |
- | Context | Get the root element |
int() |
- | integer | Get integer value of current node |
bool() |
- | boolean | Get boolean value of current node |
Example: Parsing ZUGFeRD XML
local cxpath = require("glu.cxpath")
-- Open XML file
local xml = cxpath.open("invoice.xml")
-- Register namespaces
xml:set_namespace("rsm", "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100")
xml:set_namespace("ram", "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100")
-- Query single value
local invoiceId = xml:eval("/rsm:CrossIndustryInvoice/rsm:ExchangedDocument/ram:ID")
print("Invoice ID: " .. invoiceId.string)
-- Query with nested evaluation
local seller = xml:eval("//ram:SellerTradeParty")
local name = seller:eval("ram:Name").string
local city = seller:eval("ram:PostalTradeAddress/ram:CityName").string
print("Seller: " .. name .. ", " .. city)
-- Iterate over multiple items
for item in xml:each("//ram:IncludedSupplyChainTradeLineItem") do
local desc = item:eval("ram:SpecifiedTradeProduct/ram:Name").string
local amount = item:eval("ram:SpecifiedLineTradeAgreement/ram:NetPriceProductTradePrice/ram:ChargeAmount").string
print(desc .. ": " .. amount)
endNamespace handling
For XML with namespaces, register prefixes before querying:
local xml = cxpath.open("document.xml")
-- Register multiple namespaces
xml:set_namespace("soap", "http://schemas.xmlsoap.org/soap/envelope/")
xml:set_namespace("ns", "http://example.com/namespace")
-- Use prefixes in XPath
local result = xml:eval("/soap:Envelope/soap:Body/ns:Response")Chaining is supported:
xml:set_namespace("a", "http://example.com/a")
:set_namespace("b", "http://example.com/b")
:set_namespace("c", "http://example.com/c")