CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-codehaus-groovy--groovy-xml

XML processing utilities for Apache Groovy including markup builders, parsers, and navigation tools

Pending
Overview
Eval results
Files

namespaces.mddocs/

Namespace Support

Groovy XML provides comprehensive namespace support for creating, parsing, and navigating XML documents with proper namespace handling, including namespace-aware builders, parsers, and navigation tools.

Namespace Class

Core class for managing XML namespaces and creating qualified names.

public class Namespace {
    // Constructors
    public Namespace();
    public Namespace(String uri);
    public Namespace(String uri, String prefix);
    
    // Core methods
    public QName get(String localName);
    public String getPrefix();
    public String getUri();
    
    // Utility methods
    @Override
    public boolean equals(Object obj);
    @Override
    public int hashCode();
    @Override
    public String toString();
}

Namespace Usage

// Create namespaces
def defaultNs = new Namespace('http://example.com/default')
def metaNs = new Namespace('http://example.com/metadata', 'meta')
def dataNs = new Namespace('http://example.com/data', 'data')

// Create qualified names
def titleQName = metaNs.get('title')
def itemQName = dataNs.get('item')
def rootQName = defaultNs.get('root')

println titleQName  // {http://example.com/metadata}title
println itemQName   // {http://example.com/data}item

// Use in builders
def xml = new MarkupBuilder(writer)
xml."${rootQName}" {
    "${titleQName}"('Document Title')
    "${itemQName}"(id: '1', 'Item content')
}

QName Support

QName class for representing qualified XML names with namespace information.

public class QName {
    // Constructors
    public QName(String localName);
    public QName(String namespaceURI, String localName);
    public QName(String namespaceURI, String localName, String prefix);
    
    // Accessor methods
    public String getLocalName();
    public String getNamespaceURI();
    public String getPrefix();
    
    // Utility methods
    @Override
    public boolean equals(Object obj);
    @Override
    public int hashCode();
    @Override
    public String toString();
}

QName Usage

// Create QNames directly
def qname1 = new QName('title')
def qname2 = new QName('http://example.com/ns', 'title')
def qname3 = new QName('http://example.com/ns', 'title', 'ns')

// Access QName properties
println qname3.localName      // "title"
println qname3.namespaceURI   // "http://example.com/ns"
println qname3.prefix         // "ns"

// Use in XML operations
def builder = new MarkupBuilder(writer)
builder."${qname3}" {
    content('Namespaced content')
}

Namespace-Aware Building

MarkupBuilder with Namespaces

def xml = new MarkupBuilder(writer)

// Method 1: Explicit namespace declarations
xml.root(
    'xmlns': 'http://example.com/default',
    'xmlns:meta': 'http://example.com/metadata',
    'xmlns:data': 'http://example.com/data'
) {
    'meta:header' {
        'meta:title'('Document Title')
        'meta:created'(new Date().toString())
    }
    
    'data:content' {
        'data:item'(id: '1') {
            'data:name'('Item 1')
            'data:value'('Value 1')
        }
        'data:item'(id: '2') {
            'data:name'('Item 2') 
            'data:value'('Value 2')
        }
    }
}

// Method 2: Using Namespace objects
def defaultNs = new Namespace('http://example.com/default')
def metaNs = new Namespace('http://example.com/metadata', 'meta')
def dataNs = new Namespace('http://example.com/data', 'data')

xml."${defaultNs.get('document')}"(
    'xmlns': defaultNs.uri,
    'xmlns:meta': metaNs.uri,
    'xmlns:data': dataNs.uri
) {
    "${metaNs.get('metadata')}" {
        "${metaNs.get('title')}"('Namespace Document')
    }
    
    "${dataNs.get('records')}" {
        (1..3).each { i ->
            "${dataNs.get('record')}"(id: i) {
                "${dataNs.get('value')}"("Record ${i}")
            }
        }
    }
}

StreamingMarkupBuilder with Namespaces

def smb = new StreamingMarkupBuilder()
def content = smb.bind {
    mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8')
    
    // Define namespace mappings
    namespaces = [
        '': 'http://example.com/default',
        'meta': 'http://example.com/metadata', 
        'data': 'http://example.com/data',
        'custom': 'http://example.com/custom'
    ]
    
    document(
        xmlns: namespaces[''],
        'xmlns:meta': namespaces['meta'],
        'xmlns:data': namespaces['data'],  
        'xmlns:custom': namespaces['custom']
    ) {
        
        'meta:header' {
            'meta:title'('Streaming Namespace Document')
            'meta:generator'('Groovy StreamingMarkupBuilder')
        }
        
        'data:body' {
            (1..100).each { i ->
                'data:record'(id: i, 'custom:priority': i % 3) {
                    'data:content'("Content ${i}")
                    'custom:metadata' {
                        'custom:category'("Category ${i % 5}")
                        'custom:tags' {
                            (1..(i % 3 + 1)).each { j ->
                                'custom:tag'("tag${j}")
                            }
                        }
                    }
                }
            }
        }
    }
}

content.writeTo(new FileWriter('namespaced-streaming.xml'))

Namespace-Aware Parsing

XmlParser with Namespaces

// Create namespace-aware parser
def parser = new XmlParser(false, true)  // not validating, namespace aware
def nsXml = '''<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://example.com/default"
      xmlns:meta="http://example.com/metadata"
      xmlns:data="http://example.com/data">
    <meta:header>
        <meta:title>Sample Document</meta:title>
        <meta:version>1.0</meta:version>
    </meta:header>
    <data:content>
        <data:item id="1">
            <data:name>Item 1</data:name>
            <data:value>Value 1</data:value>
        </data:item>
        <data:item id="2">
            <data:name>Item 2</data:name>
            <data:value>Value 2</data:value>
        </data:item>
    </data:content>
</root>'''

def root = parser.parseText(nsXml)

// Access namespaced elements
println root.name()  // Will include namespace information
def header = root['meta:header'][0]
def title = header['meta:title'][0].text()
def items = root['data:content'][0]['data:item']

items.each { item ->
    def name = item['data:name'][0].text()
    def value = item['data:value'][0].text()
    println "Item: ${name} = ${value}"
}

// Check namespace information
def itemNode = items[0]
println "Namespace URI: ${itemNode.namespaceURI}"
println "Local name: ${itemNode.localName}"

XmlSlurper with Namespaces

// Create namespace-aware slurper
def slurper = new XmlSlurper(false, true)  // not validating, namespace aware
def nsDoc = slurper.parseText(nsXml)

// Navigate with namespace prefixes
println nsDoc.'meta:header'.'meta:title'.text()
println nsDoc.'data:content'.'data:item'.size()

// Access all items
nsDoc.'data:content'.'data:item'.each { item ->
    println "ID: ${item.'@id'}"
    println "Name: ${item.'data:name'.text()}"
    println "Value: ${item.'data:value'.text()}"
}

// Declare namespace mappings for easier access
def mappedDoc = nsDoc.declareNamespace([
    'default': 'http://example.com/default',
    'm': 'http://example.com/metadata',
    'd': 'http://example.com/data'
])

// Use shorter prefixes
println mappedDoc.'m:header'.'m:title'.text()
println mappedDoc.'d:content'.'d:item'.'d:name'.text()

// Look up namespace URIs
println nsDoc.lookupNamespace('meta')  // "http://example.com/metadata"
println nsDoc.lookupNamespace('data')  // "http://example.com/data"

NamespaceBuilder Support

NamespaceBuilder

Builder with enhanced namespace support for complex namespace scenarios.

public class NamespaceBuilder extends NamespaceBuilderSupport {
    // Constructors
    public NamespaceBuilder();
    public NamespaceBuilder(Writer writer);
    
    // Namespace-aware building methods inherited from parent
}

NamespaceBuilderSupport

Base class providing namespace-aware building functionality.

public abstract class NamespaceBuilderSupport extends BuilderSupport {
    // Namespace management
    protected Map<String, String> namespaceMethodMap;
    protected boolean autoPrefix;
    
    // Configuration methods
    public void setAutoPrefix(boolean autoPrefix);
    public boolean getAutoPrefix();
    
    // Namespace declaration methods
    public void declareNamespace(String prefix, String namespaceURI);
    public void declareNamespace(Map<String, String> namespaceMap);
}

NamespaceBuilder Usage

def nsBuilder = new NamespaceBuilder(writer)

// Configure automatic prefixing
nsBuilder.setAutoPrefix(true)

// Declare namespaces
nsBuilder.declareNamespace('meta', 'http://example.com/metadata')
nsBuilder.declareNamespace('data', 'http://example.com/data')

// Build with automatic namespace handling
nsBuilder.root {
    'meta:information' {
        'meta:title'('Auto-prefixed Document')
        'meta:description'('Demonstrates automatic namespace handling')
    }
    
    'data:records' {
        record(id: '1') {
            'data:content'('Content 1')
        }
        record(id: '2') {
            'data:content'('Content 2')
        }
    }
}

Advanced Namespace Patterns

Dynamic Namespace Assignment

def createNamespacedDocument = { namespaceMap, data ->
    def smb = new StreamingMarkupBuilder()
    
    smb.bind {
        mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8')
        
        // Create root with all namespace declarations
        def rootAttrs = [:]
        namespaceMap.each { prefix, uri ->
            def attrName = prefix ? "xmlns:${prefix}" : 'xmlns'
            rootAttrs[attrName] = uri
        }
        
        document(rootAttrs) {
            // Use namespaces dynamically
            data.each { section ->
                def prefix = section.namespace ?: ''
                def elementName = prefix ? "${prefix}:${section.name}" : section.name
                
                "${elementName}"(section.attributes ?: [:]) {
                    section.children?.each { child ->
                        def childPrefix = child.namespace ?: ''
                        def childName = childPrefix ? "${childPrefix}:${child.name}" : child.name
                        "${childName}"(child.content)
                    }
                }
            }
        }
    }
}

// Usage
def namespaces = [
    '': 'http://example.com/default',
    'meta': 'http://example.com/metadata',
    'data': 'http://example.com/data'
]

def documentData = [
    [name: 'header', namespace: 'meta', children: [
        [name: 'title', content: 'Dynamic Document'],
        [name: 'version', content: '1.0']
    ]],
    [name: 'content', namespace: 'data', children: [
        [name: 'item', content: 'Item 1'],
        [name: 'item', content: 'Item 2']
    ]]
]

def result = createNamespacedDocument(namespaces, documentData)
result.writeTo(new FileWriter('dynamic-namespaces.xml'))

Namespace Validation and Resolution

class NamespaceValidator {
    
    static boolean validateNamespaces(GPathResult doc) {
        def namespaces = [:]
        
        // Collect all namespace declarations
        doc.depthFirst().each { node ->
            node.attributes().each { name, value ->
                if (name.startsWith('xmlns')) {
                    def prefix = name == 'xmlns' ? '' : name.substring(6)
                    namespaces[prefix] = value
                }
            }
        }
        
        // Validate all prefixed elements have declarations
        def valid = true
        doc.depthFirst().each { node ->
            def nodeName = node.name()
            if (nodeName.contains(':')) {
                def prefix = nodeName.split(':')[0]
                if (!namespaces.containsKey(prefix)) {
                    println "Undeclared namespace prefix: ${prefix}"
                    valid = false
                }
            }
        }
        
        return valid
    }
    
    static Map<String, String> extractNamespaces(GPathResult doc) {
        def namespaces = [:]
        
        doc.depthFirst().each { node ->
            node.attributes().each { name, value ->
                if (name.startsWith('xmlns')) {
                    def prefix = name == 'xmlns' ? '' : name.substring(6)
                    namespaces[prefix] = value
                }
            }
        }
        
        return namespaces
    }
}

// Usage
def slurper = new XmlSlurper(false, true)
def doc = slurper.parseText(namespacedXml)

def isValid = NamespaceValidator.validateNamespaces(doc)
def namespaces = NamespaceValidator.extractNamespaces(doc)

println "Document valid: ${isValid}"
println "Namespaces: ${namespaces}"

Namespace-Aware Transformation

def transformWithNamespaces = { inputXml, transformationRules ->
    def slurper = new XmlSlurper(false, true)
    def doc = slurper.parseText(inputXml)
    
    def smb = new StreamingMarkupBuilder()
    def result = smb.bind {
        mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8')
        
        // Extract and preserve namespaces
        def nsDeclarations = [:]
        doc.attributes().each { name, value ->
            if (name.toString().startsWith('xmlns')) {
                nsDeclarations[name] = value
            }
        }
        
        transformedDocument(nsDeclarations) {
            // Apply transformation rules while preserving namespaces
            doc.children().each { child ->
                def childName = child.name()
                def rule = transformationRules[childName]
                
                if (rule) {
                    "${rule.newName ?: childName}"(rule.newAttributes ?: [:]) {
                        if (rule.transform) {
                            rule.transform(child)
                        } else {
                            // Copy child content preserving namespaces
                            child.children().each { grandchild ->
                                "${grandchild.name()}"(grandchild.text())
                            }
                        }
                    }
                }
            }
        }
    }
    
    return result
}

// Usage
def rules = [
    'meta:header': [
        newName: 'header',
        transform: { node ->
            'title'(node.'meta:title'.text().toUpperCase())
            'processed'(new Date().toString())
        }
    ],
    'data:content': [
        newName: 'processedData',
        transform: { node ->
            node.'data:item'.each { item ->
                processedItem(id: item.'@id') {
                    originalName(item.'data:name'.text())
                    processedValue(item.'data:value'.text().reverse())
                }
            }
        }
    ]
]

def transformed = transformWithNamespaces(namespacedXml, rules)
transformed.writeTo(new FileWriter('transformed.xml'))

Namespace Best Practices

class NamespaceBestPractices {
    
    // Always use meaningful namespace URIs
    static final Map<String, String> STANDARD_NAMESPACES = [
        'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
        'xs': 'http://www.w3.org/2001/XMLSchema',
        'xml': 'http://www.w3.org/XML/1998/namespace'
    ]
    
    static void declareStandardNamespaces(MarkupBuilder builder) {
        // Always declare standard namespaces when needed
        STANDARD_NAMESPACES.each { prefix, uri ->
            builder."xmlns:${prefix}" = uri
        }
    }
    
    static String createNamespaceURI(String organization, String component, String version = null) {
        def uri = "http://${organization}/schemas/${component}"
        return version ? "${uri}/${version}" : uri
    }
    
    static boolean isValidNamespaceURI(String uri) {
        // Basic validation for namespace URIs
        return uri ==~ /^https?:\/\/.+/ || uri ==~ /^urn:.+/
    }
    
    static void validateAndBuild(Map<String, String> namespaces, Closure xmlContent) {
        // Validate all namespace URIs before building
        namespaces.each { prefix, uri ->
            if (!isValidNamespaceURI(uri)) {
                throw new IllegalArgumentException("Invalid namespace URI: ${uri}")
            }
        }
        
        def smb = new StreamingMarkupBuilder()
        def result = smb.bind {
            mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8')
            
            def rootAttrs = [:]
            namespaces.each { prefix, uri ->
                def attrName = prefix ? "xmlns:${prefix}" : 'xmlns'
                rootAttrs[attrName] = uri
            }
            
            document(rootAttrs, xmlContent)
        }
        
        return result
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-codehaus-groovy--groovy-xml

docs

builders.md

entities.md

index.md

jaxb.md

namespaces.md

navigation.md

parsing.md

streaming.md

utilities.md

tile.json