diff --git a/CMakeLists.txt b/CMakeLists.txt index 567b61a..1206e41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(fun VERSION 0.35.0 LANGUAGES C) +project(fun VERSION 0.35.1 LANGUAGES C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) diff --git a/examples/data/catalog.xml b/examples/data/catalog.xml new file mode 100644 index 0000000..57916e4 --- /dev/null +++ b/examples/data/catalog.xml @@ -0,0 +1,32 @@ + + + + Wireless Keyboard + Peripherals + 39.99 + + US + Bluetooth + AA + + + + 27" Monitor + Displays + 199.00 + + 2560x1440 + IPS + 75Hz + + + + USB-C Dock + Peripherals + 89.50 + + 2xHDMI, 3xUSB-A, 1xUSB-C PD + 65W + + + diff --git a/examples/data/employees.xml b/examples/data/employees.xml new file mode 100644 index 0000000..9ef7114 --- /dev/null +++ b/examples/data/employees.xml @@ -0,0 +1,22 @@ + + + + + Alice Doe + Senior Developer + alice@example.com + + + Bob Roe + DevOps Engineer + bob@example.com + + + + + Carol Smith + Account Executive + carol@example.com + + + diff --git a/examples/data/ns_example.xml b/examples/data/ns_example.xml new file mode 100644 index 0000000..65ea50b --- /dev/null +++ b/examples/data/ns_example.xml @@ -0,0 +1,11 @@ + + + + The Art of Fun + J. Findeisen + + + Minimal VM Design + A. Dev + + diff --git a/examples/xml_access_catalog.fun b/examples/xml_access_catalog.fun new file mode 100644 index 0000000..9a31ee8 --- /dev/null +++ b/examples/xml_access_catalog.fun @@ -0,0 +1,52 @@ +/* + * This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2025 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2025-12-09 + */ + +/* + * Demonstrate reading specific fields from an XML file using + * the minimal XML API (root name) and simple string parsing. + */ + +include + +path = "./examples/data/catalog.xml" +xml = XML() +doc = xml.from_file(path) +if (doc == 0) + print("Failed to load: ") + print(path) +else + root = xml.root(doc) + print("Root element: ") + print(xml.name(root)) + + // Show how to access specific fields by quick-and-dirty parsing + content = read_file(path) // raw XML text + // First product name + name = xml.between(content, "", "") + // First price value and its currency attribute (extract value, then attribute) + price_val = xml.between(content, "") + currency = "" + if (len(price_val) > 0) + currency = xml.between(price_val, "currency=\"", "\"") + // strip attribute tag part + price_text = xml.between(price_val, ">", "") // until end + if (len(price_text) == 0) + price_text = price_val + else + price_text = "" + + print("First product name: ") + print(name) + print("First price: ") + if (len(currency) > 0) + print(currency) + print(" ") + print(price_text) diff --git a/examples/xml_access_employees.fun b/examples/xml_access_employees.fun new file mode 100644 index 0000000..c97fcaa --- /dev/null +++ b/examples/xml_access_employees.fun @@ -0,0 +1,44 @@ +/* + * This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2025 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2025-12-09 + */ + +/* + * Access selected fields in employees.xml using minimal XML API. + */ + +include + +path = "./examples/data/employees.xml" +xml = XML() +doc = xml.from_file(path) +if (doc == 0) + print("Failed to load: ") + print(path) +else + root = xml.root(doc) + print("Root element: ") + print(xml.name(root)) + + content = read_file(path) + // Find the first block and extract its fields + first_emp = xml.between(content, "") + name = xml.between(first_emp, "", "") + role = xml.between(first_emp, "", "") + email = xml.between(first_emp, "", "") + emp_id = xml.between(first_emp, "id=\"", "\"") + + print("First employee id: ") + print(emp_id) + print("Name: ") + print(name) + print("Role: ") + print(role) + print("Email: ") + print(email) diff --git a/examples/xml_access_ns.fun b/examples/xml_access_ns.fun new file mode 100644 index 0000000..ae248e5 --- /dev/null +++ b/examples/xml_access_ns.fun @@ -0,0 +1,38 @@ +/* + * This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2025 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2025-12-09 + */ + +/* + * Access a namespaced XML file and show prefixed element names. + */ + +include + +path = "./examples/data/ns_example.xml" +xml = XML() +doc = xml.from_file(path) +if (doc == 0) + print("Failed to load: ") + print(path) +else + root = xml.root(doc) + // With namespaces, the node name may include the prefix, e.g., "ns:library" + print("Root element: ") + print(xml.name(root)) + + content = read_file(path) + // Extract first book title and author (namespace prefix bk:) + b1 = xml.between(content, "") + title = xml.between(b1, "", "") + author = xml.between(b1, "", "") + print("First book title: ") + print(title) + print("Author: ") + print(author) diff --git a/lib/io/xml.fun b/lib/io/xml.fun index 9e9d922..a726638 100644 --- a/lib/io/xml.fun +++ b/lib/io/xml.fun @@ -37,3 +37,21 @@ class XML() // Get node concatenated text content as string. fun text(this, node) return xml_text(node) + + // Utility: return substring of s between delimiters a and b. + // - If a is not found, returns "". + // - If b is an empty string, returns everything after the first occurrence of a. + // - If b is not found after a, returns "". + fun between(this, s, a, b) + i = find(s, a) + if (i < 0) + return "" + i = i + len(a) + rest = substr(s, i, len(s) - i) + if (len(b) == 0) + return rest + j = find(rest, b) + if (j < 0) + return "" + return substr(rest, 0, j) +