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)
end

Namespace 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")