Skip to content

XML and TAG Operations

Grapa provides enterprise-grade XML and HTML support with sophisticated querying capabilities that rival XPath in many ways.

Overview

XML and TAG types in Grapa are designed for structured document processing and web content generation. They support hierarchical structures with attributes, content, and nested elements using unified dot notation and powerful query patterns.

Basic Operations

XML/HTML Creation

/* Create XML element */
xml = <root><item id="1">Hello</item><item id="2">World</item></root>;

/* Create HTML element */
html = <html><head><title>Test</title></head><body><h1>Hello</h1><p>World</p></body></html>;

/* Create from string */
xml_str = "<root><item>1</item></root>";
xml = xml_str.xml();

Type Information

xml = <root><item>1</item></root>;
xml.type();                    /* Returns: $XML */
xml[0].type();                 /* Returns: $TAG */

XML Structure Access

Array-like Element Access

xml = <root><item id="1">Hello</item><item id="2">World</item></root>;

/* Access root element (required for $XML) */
xml[0]                         /* Returns: <root><item id="1">Hello</item><item id="2">World</item></root> */

/* Access child elements */
xml[0][0]                      /* Returns: <item id="1">Hello</item> */
xml[0][1]                      /* Returns: <item id="2">World</item> */

/* Access element content */
xml[0][0][0]                   /* Returns: "Hello" */
xml[0][1][0]                   /* Returns: "World" */

/* Get element count */
xml[0].len()                   /* Returns: 2 (number of child elements) */
xml[0][0].len()                /* Returns: 1 (content count) */

Dot Notation Access

xml = <root><item id="1">Hello</item><item id="2">World</item></root>;

/* Direct dot notation access */
xml.root                       /* Returns: <root><item id="1">Hello</item><item id="2">World</item></root> */
xml.root.item                  /* Returns: <item id="1">Hello</item> */
xml.root.item[0]               /* Returns: "Hello" */

/* Access nested structures */
xml.root.item.attr             /* Returns: {"id":"1"} */
xml.root.item.attr.id          /* Returns: "1" */

Attribute Access

xml = <root><item id="1" class="test">Hello</item><item id="2">World</item></root>;

/* Access all attributes of an element */
xml[0][0].attr                 /* Returns: {"id":"1","class":"test"} */

/* Access specific attributes */
xml[0][0].attr.id              /* Returns: "1" */
xml[0][0].attr.class           /* Returns: "test" */

/* Access attributes via dot notation */
xml.root.item.attr.id          /* Returns: "1" */
xml.root.item.attr.class       /* Returns: "test" */

XML Rotation

XML structures support left and right rotation operations for reordering child elements:

Left Rotation (.lrot())

xml = <root><item id="1">First</item><item id="2">Second</item><item id="3">Third</item></root>;

xml.lrot();                              /* <root><item id="2">Second</item><item id="3">Third</item><item id="1">First</item></root> */
xml.lrot(2);                             /* <root><item id="3">Third</item><item id="1">First</item><item id="2">Second</item></root> */
xml.lrot(0);                             /* <root><item id="1">First</item><item id="2">Second</item><item id="3">Third</item></root> (no change) */

Right Rotation (.rrot())

xml = <root><item id="1">First</item><item id="2">Second</item><item id="3">Third</item></root>;

xml.rrot();                              /* <root><item id="3">Third</item><item id="1">First</item><item id="2">Second</item></root> */
xml.rrot(2);                             /* <root><item id="2">Second</item><item id="3">Third</item><item id="1">First</item></root> */
xml.rrot(0);                             /* <root><item id="1">First</item><item id="2">Second</item><item id="3">Third</item></root> (no change) */

Note: Rotation methods preserve all child elements and their attributes while reordering them. For empty XML or single-element XML, rotation has no effect.

Advanced Element Finding (.findall())

The .findall() method provides enterprise-grade querying capabilities with support for complex patterns and logical operations.

Basic Queries

xml = <root><item id="1">Hello</item><item id="2">World</item></root>;

/* Find by tag name */
xml.findall({name:"item"})     /* Returns: <item id="1">Hello</item><item id="2">World</item> */

/* Find by content value */
xml.findall({value:"Hello"})   /* Returns: <item id="1">Hello</item> */

/* Find by attributes */
xml.findall({attr:{id:"2"}})   /* Returns: <item id="2">World</item> */

/* Find by tag name and attributes */
xml.findall({name:"item", attr:{id:"1"}}) /* Returns: <item id="1">Hello</item> */

Complex Attribute Queries

xml = <root><item id="1" class="test">Hello</item><item id="2" class="prod">World</item></root>;

/* Multiple attributes */
xml.findall({attr:{id:"1", class:"test"}}) /* Returns: <item id="1" class="test">Hello</item> */

/* Tag name with multiple attributes */
xml.findall({name:"item", attr:{id:"1", class:"test"}}) /* Returns: <item id="1" class="test">Hello</item> */

Logical Operators

xml = <root><item id="1">Hello</item><title>Test</title></root>;

/* AND logic */
xml.findall({and:[{name:"item"}, {attr:{id:"1"}}]}) /* Returns: <item id="1">Hello</item> */

/* OR logic */
xml.findall({or:[{name:"item"}, {name:"title"}]}) /* Returns: <item id="1">Hello</item><title>Test</title> */

/* NAND logic */
xml.findall({nand:[{name:"item"}, {attr:{id:"2"}}]}) /* Returns: <item id="1">Hello</item> */

Content Matching

xml = <root><item id="1">Hello</item><item id="2">World</item></root>;

/* Exact content match */
xml.findall({value:"Hello"})   /* Returns: <item id="1">Hello</item> */

/* Multiple content values */
xml.findall({value:["Hello", "World"]}) /* Returns: <item id="1">Hello</item><item id="2">World</item> */
xml = <root><header><item id="1">Hello</item></header><body><item id="2">World</item></body></root>;

/* Searches through ALL nested elements */
xml.findall({name:"item"})     /* Returns: <item id="1">Hello</item><item id="2">World</item> */

Working with .findall() Results

xml = <root><item id="1">Hello</item><item id="2">World</item><item id="3">Another</item></root>;

/* Get all results */
results = xml.findall({name:"item"});
results.len()                  /* Returns: 3 */

/* Access individual results */
first = results[0];            /* Returns: <item id="1">Hello</item> */
second = results[1];           /* Returns: <item id="2">World</item> */

/* Access attributes of results */
first.attr                     /* Returns: {"id":"1"} */
first.attr.id                  /* Returns: "1" */
first[0]                       /* Returns: "Hello" */

HTML Element Finding

html = <html><head><title>Test</title></head><body><h1>Hello</h1><p>World</p><p>Another</p><div><p>Nested</p></div></body></html>;

/* Find all paragraph elements (including nested) */
html.findall({name:"p"})       /* Returns: <p>World</p><p>Another</p><p>Nested</p> */

/* Find all heading elements */
html.findall({name:"h1"})      /* Returns: <h1>Hello</h1> */

/* Find elements by class */
html.findall({name:"div", attr:{class:"container"}})

XML to LIST Conversion

Using .list() Method

xml = <root><item id="1">Hello</item><item id="2">World</item></root>;

/* Convert XML to LIST structure */
list = xml.list();             /* Returns: {{"root":[{},[{"item":[{"id":"1"},["Hello"]]},{"item":[{"id":"2"},["World"]]}]]}} */

/* Access converted data */
list.root[1][0].item[1][0]     /* Returns: "Hello" */
list.root[1][1].item[1][0]     /* Returns: "World" */

Complex Structure Conversion

xml = <html><head><title>Test</title></head><body><h1>Hello</h1></body></html>;

/* Convert complex nested structure */
list = xml.list();             /* Complex nested LIST structure */

/* Access nested elements */
list.html[1][0].head[1][0].title[1][0]  /* Returns: "Test" */
list.html[1][1].body[1][0].h1[1][0]     /* Returns: "Hello" */

String Output

Converting to String

xml = <root><item id="1">Hello</item><item id="2">World</item></root>;

/* Get XML string representation */
xml.echo();                    /* Outputs: <root><item id="1">Hello</item><item id="2">World</item></root> */
xml.str();                     /* Returns: <root><item id="1">Hello</item><item id="2">World</item></root> */

/* Get string representation of individual elements */
xml[0][0].str();               /* Returns: <item id="1">Hello</item> */

Integration with Other Types

XML and Arrays

xml = <root><item>1</item><item>2</item><item>3</item></root>;

/* Iterate over elements */
for (i = 0; i < xml[0].len(); i++) {
    xml[0][i].echo();          /* Output each item element */
}

XML and Lists

/* XML elements behave like lists for attribute access */
first_item = xml[0][0];        /* First item element */
first_item.attr.id             /* Access attribute like a list property */

/* Convert XML to LIST for complex processing */
list_data = xml.list();        /* Full LIST conversion */

Performance Considerations

  • Efficient Parsing: XML is parsed efficiently during creation
  • Array-like Access: Direct indexing provides fast element access
  • Powerful Finding: .findall() method supports complex queries with logical operators
  • Memory Efficient: Optimized storage for XML structures
  • Recursive Search: Efficient traversal of nested structures

Limitations

The following features are not currently implemented or fully supported: - .find() method - Use findall()[0] instead (not needed given .findall()'s power) - .tag property - Tag names are embedded in string representation, direct .tag property is not available - .children property - Use array indexing [0], [1], etc. - .parent property - Not implemented - .siblings property - Not implemented - .to_json() method - Not implemented - XML manipulation operators (+=, -=, ++=) - Not implemented

Best Practices

Element Access

/* Use array indexing for direct access to children */
xml[0][0]                      /* First child element */

/* Use dot notation for direct access to named children */
xml.root.item                  /* First 'item' child of 'root' */

/* Use .findall() for complex queries and recursive searches */
xml.findall({name:"item", attr:{class:"highlight"}})

/* Use .attr for attribute access */
xml[0][0].attr.id              /* Access specific attribute */

Error Handling

/* Check for existence before accessing properties or elements */
if (xml.root) {
    if (xml.root.item) {
        xml.root.item.echo();
    }
}

See also