Skip to content

core.base.xml

This module provides a lightweight DOM-style XML toolkit that works inside Xmake's sandbox environment. It focuses on predictable data structures, JSON-like usability, and optional streaming so you can parse large XML documents without building the entire tree.

TIP

To use this module, you need to import it first: import("core.base.xml")

The XML module features:

  • DOM-style node structure using plain Lua tables
  • Streaming parser for large files (xml.scan)
  • XPath-like queries (xml.find)
  • Convenient file I/O helpers (xml.loadfile, xml.savefile)
  • Support for comments, CDATA, DOCTYPE, and unquoted attributes
  • Pretty printing with customizable indentation

XML nodes are plain Lua tables with the following structure:

lua
{
    name     = "element-name" | nil,  -- only for element nodes
    kind     = "element" | "text" | "comment" | "cdata" | "doctype" | "document",
    attrs    = { key = value, ... } or nil,
    text     = string or nil,
    children = { child1, child2, ... } or nil,
    prolog   = { comment/doctype nodes before root } or nil
}

xml.decode

  • Parse XML string into a document node

Function Prototype

API

lua
xml.decode(xml_string: <string>, options?: <table>)

Parameter Description

ParameterDescription
xml_stringXML string to parse
optionsOptional table with parsing options

Options

OptionDescription
trim_text = trueTrim leading/trailing whitespace from text nodes
keep_whitespace_nodes = trueKeep text nodes that contain only whitespace

Return Value

TypeDescription
tableDocument node (root of the XML tree)

Usage

lua
import("core.base.xml")

local doc = assert(xml.decode([[
<?xml version="1.0"?>
<root id="1">
  <item id="foo">hello</item>
</root>
]]))

xml.encode

  • Encode document node to XML string

Function Prototype

API

lua
xml.encode(doc: <table>, options?: <table>)

Parameter Description

ParameterDescription
docDocument node to encode
optionsOptional table with encoding options

Options

OptionDescription
pretty = trueEnable pretty printing
indentNumber of spaces for indentation (default: 2)
indentcharCharacter to use for indentation (default: " ")

Return Value

TypeDescription
stringXML string representation

Usage

lua
import("core.base.xml")

local doc = xml.decode("<root><item>hello</item></root>")
local pretty = assert(xml.encode(doc, {pretty = true, indent = 2}))

xml.loadfile

  • Load XML document from file

Function Prototype

API

lua
xml.loadfile(filepath: <string>, options?: <table>)

Parameter Description

ParameterDescription
filepathPath to XML file
optionsOptional table with parsing options (same as xml.decode)

Return Value

TypeDescription
tableDocument node

Usage

lua
import("core.base.xml")

local plist = assert(xml.loadfile("Info.plist"))

xml.savefile

  • Save XML document to file

Function Prototype

API

lua
xml.savefile(filepath: <string>, doc: <table>, options?: <table>)

Parameter Description

ParameterDescription
filepathPath to save XML file
docDocument node to save
optionsOptional table with encoding options (same as xml.encode)

Return Value

TypeDescription
booleanReturns true on success

Usage

lua
import("core.base.xml")

local doc = xml.loadfile("Info.plist")
-- ... modify nodes ...
assert(xml.savefile("Info.plist", doc, {pretty = true, indent = 2}))

xml.find

  • Find node using XPath-like query

Function Prototype

API

lua
xml.find(doc: <table>, xpath: <string>)

Parameter Description

ParameterDescription
docDocument node or any node to search from
xpathXPath-like query string

Return Value

TypeDescription
table|nilFound node or nil if not found

Usage

lua
import("core.base.xml")

local doc = assert(xml.loadfile("config.xml"))

-- Find by path
local element = xml.find(doc, "/root/item")

-- Find by attribute
local item = xml.find(doc, "//item[@id='foo']")

-- Find by text content
local node = xml.find(doc, "//string[text()='value']")

xml.scan

  • Stream parse XML and call callback for each node

Function Prototype

API

lua
xml.scan(xml_string: <string>, callback: <function>, options?: <table>)

Parameter Description

ParameterDescription
xml_stringXML string to parse
callbackFunction called for each node: function(node) -> boolean
optionsOptional table with parsing options (same as xml.decode)

Callback Return Value

Return false from the callback to stop scanning immediately.

Usage

lua
import("core.base.xml")

local found
xml.scan(plist_text, function(node)
    if node.name == "key" and xml.text_of(node) == "NSPrincipalClass" then
        found = node
        return false -- early terminate
    end
end)

xml.scan walks nodes as they are completed; returning false stops the scan immediately. This is ideal for large files when you only need a few entries.

xml.text_of

  • Get text content of a node

Function Prototype

API

lua
xml.text_of(node: <table>)

Parameter Description

ParameterDescription
nodeNode to extract text from

Return Value

TypeDescription
stringText content of the node

Usage

lua
import("core.base.xml")

local node = xml.find(doc, "//item[@id='foo']")
local text = xml.text_of(node)  -- Returns "hello"

xml.text

  • Create a text node

Function Prototype

API

lua
xml.text(text: <string>)

Parameter Description

ParameterDescription
textText content

Return Value

TypeDescription
tableText node

Usage

lua
import("core.base.xml")

local textnode = xml.text("hello")

xml.empty

  • Create an empty element node

Function Prototype

API

lua
xml.empty(name: <string>, attrs?: <table>)

Parameter Description

ParameterDescription
nameElement name
attrsOptional attributes table

Return Value

TypeDescription
tableElement node

Usage

lua
import("core.base.xml")

local empty = xml.empty("br", {class = "line"})

xml.comment

  • Create a comment node

Function Prototype

API

lua
xml.comment(text: <string>)

Parameter Description

ParameterDescription
textComment text

Return Value

TypeDescription
tableComment node

Usage

lua
import("core.base.xml")

local comment = xml.comment("generated by xmake")

xml.cdata

  • Create a CDATA node

Function Prototype

API

lua
xml.cdata(text: <string>)

Parameter Description

ParameterDescription
textCDATA text

Return Value

TypeDescription
tableCDATA node

Usage

lua
import("core.base.xml")

local cdata_node = xml.cdata("if (value < 1) {...}")

xml.doctype

  • Create a DOCTYPE node

Function Prototype

API

lua
xml.doctype(declaration: <string>)

Parameter Description

ParameterDescription
declarationDOCTYPE declaration string

Return Value

TypeDescription
tableDOCTYPE node

Usage

lua
import("core.base.xml")

local doctype = xml.doctype('plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"')

Complete Example

lua
import("core.base.xml")

-- Parse XML string
local doc = assert(xml.decode([[
<?xml version="1.0"?>
<root id="1">
  <item id="foo">hello</item>
</root>
]]))

-- Find and modify nodes
local item = assert(xml.find(doc, "//item[@id='foo']"))
item.attrs.lang = "en"             -- mutate attrs directly
item.children = {xml.text("world")} -- replace existing text node

-- Add comment
table.insert(doc.children, xml.comment("generated by xmake"))

-- Encode with pretty printing
local pretty = assert(xml.encode(doc, {pretty = true}))
assert(xml.savefile("out.xml", doc, {pretty = true}))