Releases: Alipsa/gsvg
Ver 1.0.0
Version 1.0.0 - 2026-01-18
Added
gsvg-exportmodule for rendering/optimization.gsvg-examplesmodule with example groovy script using the gsv library.- CSS selector queries (
css,cssFirst) alongside XPath. - Rendering benchmarks and expanded performance documentation.
Changed
- Parsing now preserves raw attribute strings; numeric precision formatting only applies to programmatic attribute setting.
- Merge/cloning paths optimized for lower overhead.
Ver 0.9.0
Polish and Production Readiness
This release represents the final polish phase before v1.0, focusing on file size optimization, accessibility,
developer experience enhancements, and comprehensive documentation. All features are fully backward compatible
and production-ready.
Numeric Precision Control
- Intelligent number formatting with configurable precision for 30-50% file size reduction
- New
NumberFormatterutility (se.alipsa.groovy.svg.utils.NumberFormatter):- Default precision: 3 decimals (matching SVGO and Adobe Illustrator industry standards)
- Automatic removal of trailing zeros (12.120 → 12.12)
- Clean integer output (50.0 → 50)
- Thread-local global configuration:
setDefaultPrecision(),resetPrecision() - Per-document precision:
svg.setMaxPrecision(2)
- Integrated at
SvgElement.addAttribute()level - all numeric attributes automatically formatted - Full calculation precision maintained - rounding only applied at serialization
- Benefits: 30-50% file size reduction for coordinate-heavy graphics, cleaner output, industry standard alignment
- 100% backward compatible - no API changes, automatic optimization
// Automatic precision control:
circle.cx(12.123456789) // Outputs: cx="12.123" (default 3 decimals)
rect.x(50.0) // Outputs: x="50" (no trailing zeros)
line.x1(10.12) // Outputs: x1="10.12" (preserves existing precision)
// Configuration:
NumberFormatter.setDefaultPrecision(5) // Global setting (thread-local)
svg.setMaxPrecision(2) // Per-document override
NumberFormatter.resetPrecision() // Reset to default (3)Accessibility Helpers
- Complete ARIA support with helper methods and validation
- 15 ARIA methods added to
SvgElement(inherited by all elements):role(role)/getRole()- Set/get ARIA roleariaLabel(label)/getAriaLabel()- Accessible nameariaLabelledBy(ids)/getAriaLabelledBy()- Reference to label elementsariaDescribedBy(ids)/getAriaDescribedBy()- Reference to description elementsariaHidden(hidden)/isAriaHidden()- Hide from screen readersariaLive(polite|assertive|off)/getAriaLive()- Live region updatesdecorative()- Convenience:role='presentation'+aria-hidden='true'accessibleImage(label)- Convenience:role='img'+ariaLabel(label)
- New
AccessibilityRulefor validation (se.alipsa.groovy.svg.validation.rules.AccessibilityRule):- Validates root SVG has accessible name (WARNING)
- Validates SVG with
role='img'has label (WARNING) - Validates interactive elements have labels (WARNING)
- Validates ARIA reference IDs exist (ERROR)
- Validates decorative elements don't need labels
- New validation factory:
ValidationEngine.createAccessibility()for accessibility-only validation - Comprehensive documentation in new
doc/accessibility.mdguide
// Make SVG accessible:
svg.role('img').ariaLabel('Monthly revenue chart showing growth trend')
// Or use title/desc:
svg.addTitle('Revenue Dashboard')
svg.addDesc('Interactive chart showing monthly revenue from January to December')
// Interactive elements:
circle.ariaLabel('January sales: $50,000 - Click for details')
.addAttribute('tabindex', '0')
// Decorative elements:
svg.addRect().decorative() // Sets role='presentation' + aria-hidden='true'
// Validate accessibility:
ValidationEngine engine = ValidationEngine.createAccessibility()
ValidationReport report = engine.validate(svg)Builder Pattern Enhancements
Effects Presets
- New
Effectsutility (se.alipsa.groovy.svg.effects.Effects) with 7 preset filters:dropShadow(defs, options)- Configurable drop shadow effectglow(defs, options)- Glow/halo effect with color and strengthblur(defs, blur, id)- Gaussian blur filtergrayscale(defs, id)- Convert to grayscalesepia(defs, id)- Sepia tone effectbrightness(defs, options)- Adjust brightness (0.0-2.0)contrast(defs, options)- Adjust contrast (0.0-2.0)applyFilter(element, filter)- Apply filter to element
- Map-based configuration for flexibility and sensible defaults
- Integrated with existing Filter API - returns configured Filter objects
Defs defs = svg.addDefs()
// Drop shadow:
Filter shadow = Effects.dropShadow(defs,
id: 'shadow1', dx: 3, dy: 3, blur: 5, opacity: 0.6)
element.filter('url(#shadow1)')
// Glow effect:
Filter glow = Effects.glow(defs,
id: 'glow1', color: 'yellow', blur: 5, strength: 3)
// Color adjustments:
Filter gray = Effects.grayscale(defs, 'gray1')
Filter bright = Effects.brightness(defs, amount: 1.5)Shape Presets
- New
Shapesutility (se.alipsa.groovy.svg.presets.Shapes) with 5 common shape generators:roundedRect(parent, options)- Rectangle with uniform corner radiusstar(parent, options)- Multi-point star polygonarrow(parent, options)- Arrow path with configurable headregularPolygon(parent, options)- Regular polygons (triangle, hexagon, etc.)speechBubble(parent, options)- Speech bubble with tail
- Automatic path calculations for complex geometries
- Uses PathBuilder for precise path construction
// 5-point star:
Polygon star = Shapes.star(svg,
cx: 150, cy: 150, points: 5, outerRadius: 50, innerRadius: 25)
// Arrow:
Path arrow = Shapes.arrow(svg,
x1: 10, y1: 50, x2: 100, y2: 50, headSize: 15, headAngle: 30)
// Speech bubble:
Path bubble = Shapes.speechBubble(svg,
x: 10, y: 10, width: 100, height: 60, tailX: 50, tailY: 80)Template System
- New
Templatebase class (se.alipsa.groovy.svg.templates.Template) for reusable SVG patterns:abstract apply(parent, params)- Apply template with parametersgetDefaults()- Define default parameter valuesmergeParams(params)- Merge user params with defaults- Extensible architecture for custom templates
ChartLegendexample template (se.alipsa.groovy.svg.templates.ChartLegend):- Configurable chart legend with color swatches and labels
- 12 configuration parameters (position, size, styling, border, etc.)
- Production-ready for data visualization
// Use ChartLegend template:
ChartLegend legend = new ChartLegend()
legend.apply(svg, [
x: 450, y: 50,
items: [
[color: 'red', label: 'Series 1'],
[color: 'blue', label: 'Series 2'],
[color: 'green', label: 'Series 3']
]
])
// Create custom templates:
class ButtonTemplate extends Template {
SvgElement apply(AbstractElementContainer parent, Map params) {
G button = parent.addG()
button.addRect()
.x(params.x).y(params.y)
.width(100).height(50)
.rx(5).fill('blue')
button.addText(params.label)
.x(params.x + 50).y(params.y + 30)
.textAnchor('middle').fill('white')
return button
}
}DSL Configuration Closures
- Closure-based configuration for all common shapes:
- Added 9 DSL methods to
AbstractElementContainer:addCircle{},addRect{},addEllipse{},addLine{},addPath{},addText{},addG{},addPolygon{},addPolyline{} - Uses
@DelegatesToannotation for IDE autocomplete support - Groovy-idiomatic syntax for cleaner SVG construction
- Method chaining still works within closures
- Added 9 DSL methods to
// DSL-style configuration:
svg.addCircle {
cx 100
cy 100
r 50
fill 'red'
stroke 'black'
strokeWidth 2
}
svg.addRect {
x 10
y 10
width 100
height 50
fill 'blue'
}
svg.addG {
fill 'green'
stroke 'darkgreen'
// Add children within closure:
addCircle().cx(50).cy(50).r(20)
addRect().x(100).y(30).width(40).height(40)
}Quick Wins (Developer Experience)
Clone with Modifications
- New
cloneWith(parent, modifications)method onSvgElement:- Clone element and apply attribute modifications in one operation
- Map-based modifications for convenience
- Useful for creating element variations
Circle original = svg.addCircle()
.cx(100).cy(100).r(50).fill('red')
// Clone with modifications:
Circle blue = original.cloneWith(svg, [fill: 'blue', cx: 250])
Circle large = original.cloneWith(svg, [r: 75, fill: 'green', cx: 400])Shape Factory Methods
- 5 convenience factory methods added directly to
Svgclass:createRoundedRect(options)- Rounded rectanglecreateStar(options)- Star polygoncreateArrow(options)- Arrow pathcreateRegularPolygon(options)- Regular polygonscreateSpeechBubble(options)- Speech bubble
- Delegates to
Shapesutility but more discoverable on mainSvgclass - Fluent API integration - returns configured elements for method chaining
// More discoverable than Shapes.star():
Polygon star = svg.createStar(
cx: 100, cy: 100, points: 5, outerRadius: 50)
Rect rounded = svg.createRoundedRect(
x: 10, y: 10, width: 100, height: 60, radius: 10)
Path arrow = svg.createArrow(
x1: 10, y1: 50, x2: 100, y2: 50, headSize: 15)Null-Safe Attribute Access
- 3 new
getAttributeOrDefault()methods onSvgElement:getAttributeOrDefault(name, defaultValue)- Simple string attributegetAttributeOrDefault(qname, defaultValue)- Qualified namegetAttributeOrDefault(prefix, localName, defaultValue)- Namespaced
- Prevents NullPointerException when accessing missing attributes
- Cleaner code - no manual null checking needed
// Safe access with defaults:
String fill = circle.getAttributeOrD...Ver 0.8.0
Advanced Features
This release implements three major features: CSS integration, validation helpers, and performance benchmarks. All features are fully backward compatible and opt-in.
CSS Integration
- New CSS object model with ph-css 8.1.1 integration for robust parsing
- CSS classes (
se.alipsa.groovy.svg.css.CssRule,CssStyleSheet,CssParser) - Style element enhancements on
Style:addRule(selector, declarations)- Add CSS rules programmaticallyremoveRule(selector)- Remove rules by selectorgetStyleSheet()- Get parsed CssStyleSheet objectsetStyleSheet(CssStyleSheet)- Replace stylesheetgetRules()- Get all CSS rules
- Inline style Map API on
SvgElement:style(Map<String, Object>)- Set inline styles from mapgetStyleMap()- Parse inline style to mapgetStyleProperty(property)- Get specific style property
- CSS class management on
SvgElement:addClass(className)- Add CSS classremoveClass(className)- Remove CSS classtoggleClass(className)- Toggle CSS classhasClass(className)- Check if class existsgetClasses()- Get all CSS classes as list
- Full method chaining support for all CSS methods
- Maintains backward compatibility - all string-based style/class APIs still work
// CSS object model:
def style = svg.addStyle()
style.addRule('.highlight', [fill: 'red', stroke: 'black', 'stroke-width': '2'])
style.addRule('#logo', [transform: 'scale(2)'])
// Inline style Map API:
rect.style([fill: 'red', stroke: 'blue', 'stroke-width': '2'])
def fillColor = rect.getStyleProperty('fill') // 'red'
// Class management:
rect.addClass('highlight').addClass('selected')
rect.removeClass('selected')
if (rect.hasClass('highlight')) { /* ... */ }Validation Helpers
- Complete opt-in validation system - library remains permissive by default
- Validation infrastructure:
ValidationLevelenum (ERROR, WARNING, INFO)ValidationIssue- Immutable issue objects with level, message, element pathValidationReport- Aggregates issues with query methodsValidationRuleinterface - Extensible validation rule systemValidationEngine- Orchestrates validation with customizable rule sets
- Six core validation rules:
RequiredAttributeRule- Validates required attributes (circle needs cx/cy/r, etc.)AttributeValueRule- Validates attribute value domains and rangesElementNestingRule- Validates valid parent-child relationshipsViewBoxRule- Validates viewBox format and dimensionsHrefRule- Validates href/xlink:href references point to existing IDsDuplicateIdRule- Detects duplicate element IDs
- Validation methods on
SvgandSvgElement:validate()- Validate with default rulesvalidate(ValidationEngine)- Validate with custom rulesisValid()- Quick validation check (no errors)
- Optimized performance - All rules run in O(N) time
- No breaking changes - All invalid SVG creation continues to work, validation is purely opt-in
// Basic validation:
def report = svg.validate()
if (report.isValid()) {
// No errors (warnings/info don't fail validation)
}
// Inspect issues:
report.getErrors().each { println "ERROR: ${it.message}" }
report.getWarnings().each { println "WARNING: ${it.message}" }
report.getInfo().each { println "INFO: ${it.message}" }
// Custom validation:
def engine = ValidationEngine.createDefault()
engine.removeRule("VIEWBOX_RULE") // Disable specific rule
svg.validate(engine)Performance Benchmarks
- Complete JMH benchmark suite (JMH 1.37)
- 9 benchmark classes covering all major operations:
ParsingBenchmark- Parse simple/medium/large/complex SVGsSerializationBenchmark- toXml() and toXmlPretty() performanceCreationBenchmark- Element creation and fluent API chainingMergingBenchmark- Horizontal/vertical/on-top merge performanceCloningBenchmark- Deep copy operationsUtilityBenchmark- Color, PathBuilder, ViewBox utilitiesSelectionBenchmark- Type filtering, XPath queries, descendantsRunAllBenchmarks- Convenience runner for all benchmarksBenchmarkBase- Shared benchmark infrastructure
- 4 test SVG files in
src/test/resources/benchmarks/:simple.svg(10 elements) - Basic operationsmedium.svg(100 elements) - Typical documentslarge.svg(1000 elements) - Stress testingcomplex.svg- Real-world structure
- Benchmark sanity tests - 8 tests ensuring benchmarks execute without errors
- Comprehensive results documented in
doc/benchmarks.mdwith performance analysis - Easy to run:
mvn exec:java -Dexec.classpathScope=test -Dexec.mainClass="benchmarks.RunAllBenchmarks"
Tests
- Added 146 new tests (28 CSS tests, 73 validation tests, 8 benchmark tests, 37 rule tests)
- Total test count: 593 tests (was 447 in v0.7.0)
- 100% pass rate
- Comprehensive coverage of all new features
Bug Fixes
- Fixed HrefRule performance issue (O(N²) → O(N) optimization)
- Fixed HrefRule namespace exception when xlink namespace not bound
- Added proper exception handling for namespace-prefixed attributes
Documentation
- Updated
kanban/in-progress/svgTodo.mdmarking Phase 3 complete - Added extensive inline documentation with usage examples
- All new classes fully documented with Groovydoc
- Library status updated to 593 tests
API additions/updates
se.alipsa.groovy.svg.css.CssRule: CSS rule value objectse.alipsa.groovy.svg.css.CssStyleSheet: CSS stylesheet managementse.alipsa.groovy.svg.css.CssParser: CSS parsing utilities (package-private)Style:addRule(),removeRule(),getStyleSheet(),setStyleSheet(),getRules()SvgElement:style(Map),getStyleMap(),getStyleProperty(),addClass(),removeClass(),toggleClass(),hasClass(),getClasses()Svg:validate(),validate(ValidationEngine),isValid()SvgElement:validate(),isValid()se.alipsa.groovy.svg.validation.*: Complete validation infrastructurese.alipsa.groovy.svg.validation.rules.*: Six validation rule implementations
Dependency updates
- Added ph-css 8.1.1 for css management
- Added JMH 1.37 for benchmarking (test scope)
Breaking changes
- None - all additions are backward compatible and opt-in
Ver 0.7.0
This release implements features focusing on advanced path manipulation, coordinate system utilities, and powerful element selection methods.
Path Data Manipulation
- New
PathBuilderclass (se.alipsa.groovy.svg.utils.PathBuilder) for fluent path construction - All SVG path commands supported:
- MoveTo:
moveTo(x, y),moveToRel(dx, dy),M(),m() - LineTo:
lineTo(x, y),lineToRel(dx, dy),L(),l() - Horizontal/Vertical:
horizontalTo(x),verticalTo(y),H(),V(),h(),v() - Cubic bezier:
curveTo(),curveToRel(),smoothCurveTo(),C(),S(),c(),s() - Quadratic bezier:
quadTo(),quadToRel(),smoothQuadTo(),Q(),T(),q(),t() - Arcs:
arc(),arcRel(),A(),a() - Close path:
closePath(),Z(),z()
- MoveTo:
- Fluent API: Full method chaining support for building complex paths
- Path parsing:
PathBuilder.parse(pathString)to parse and extend existing paths - Path integration:
Path.d(PathBuilder)accepts PathBuilder objects directly - Utility methods:
copy(),getCommands(),isEmpty(),toString()
ViewBox / Coordinate Helpers
- New
ViewBoxclass (se.alipsa.groovy.svg.utils.ViewBox) for viewport management - Creation methods:
ViewBox.of(minX, minY, width, height)- Create viewBoxViewBox.parse(string)- Parse viewBox strings
- Transformations (all immutable, return new ViewBox):
scale(factor),scale(scaleX, scaleY)- Scale dimensionstranslate(dx, dy)- Shift coordinatesexpand(margin)- Add marginscenterAt(cx, cy)- Center at pointwithAspectRatio(ratio)- Set aspect ratiofitToContain(other)- Fit viewBox to contain another
- Query methods:
getCenterX(),getCenterY(),getMaxX(),getMaxY(),getAspectRatio()contains(x, y),contains(viewBox),intersects(viewBox)
- Integration with Svg, Symbol, and View elements:
svg.viewBox(ViewBox)- Accept ViewBox objectssvg.viewBox(minX, minY, width, height)- Four-parameter conveniencesvg.getViewBoxObject()- Parse and return ViewBox object
- Output:
toString()produces SVG-compatible viewBox strings,toMap()for data access
Enhanced Element Selection
- Filter and find methods:
filter(predicate)- Filter elements by closurefindAll(Class, predicate)- Find all of a type, optionally filteredfindFirst(predicate)- Find first matching elementfindFirst(Class)- Find first of a type
- Recursive search:
descendants()- Get all descendant elements recursivelydescendants(Class)- Get all descendants of a specific type
- XPath queries:
xpath(query)- Execute XPath queries on the SVG DOM- Full XPath 1.0 support via dom4j/Jaxen
- Aggregate operations:
count(predicate)- Count matching elementsany(predicate)- Check if any element matchesall(predicate)- Check if all elements matchcollect(transform)- Transform and collect values from elements
Tests
- Added 113 new tests (29 PathBuilder tests, 54 ViewBox tests, 30 enhanced selection tests)
- Total test count: 447 tests (all passing)
- 100% pass rate
- Comprehensive coverage of new utilities
- XPath namespace handling fully functional with transparent query transformation
Documentation
- Updated
kanban/in-progress/svgTodo.mdmarking Phase 2 complete - Added extensive inline documentation with usage examples
- All new classes fully documented with Groovydoc
API additions/updates
se.alipsa.groovy.svg.utils.PathBuilder: Complete path building utilityse.alipsa.groovy.svg.utils.ViewBox: ViewBox manipulation and coordinate helpersPath:d(PathBuilder),builder(PathBuilder)methodsSvg,Symbol,View:viewBox(ViewBox),viewBox(minX, minY, width, height),getViewBoxObject()methodsElementContainer:filter(),findAll(),findFirst(),descendants(),xpath(),count(),any(),all(),collect()methods
Breaking changes
- None - all additions are backward compatible
Ver 0.6.0
Ease of Use Enhancements
This release focuses on improving API ergonomics and developer experience with new utilities for common SVG operations.
Transform Utilities
- Fluent transform API: Added transform methods to
AbstractShapefor all SVG transformationsrotate(angle)androtate(angle, cx, cy)- rotation with optional center pointtranslate(tx, ty)andtranslate(tx)- translation (dual-axis or x-axis only)scale(sx, sy)andscale(s)- scaling (non-uniform or uniform)skewX(angle)andskewY(angle)- skewing transformationsmatrix(a, b, c, d, e, f)- direct matrix transformtransform(string)- backward-compatible string setter
- Chaining support: All transform methods return
thisfor method chaining - Append behavior: Transforms append to existing transform attribute (e.g.,
rect.rotate(45).translate(10, 20)) - Backward compatible: String-based transform API still works (
rect.transform('rotate(45)'))
Color Utilities
- New
Colorclass (se.alipsa.groovy.svg.utils.Color) for color creation and manipulation - Multiple creation methods:
Color.rgb(r, g, b)- RGB values (0-255)Color.rgba(r, g, b, a)- RGBA with alpha (0.0-1.0)Color.hex(string)- Hex colors (#RGB, #RRGGBB, #RRGGBBAA)Color.hsl(h, s, l)andColor.hsla(h, s, l, a)- HSL/HSLA valuesColor.named(name)- Named colors (147 SVG color names supported)Color.parse(string)- Auto-detect and parse any color format
- Color manipulation:
withAlpha(a)- Create new color with different alphadarken(amount)- Darken by percentage (0.0-1.0)lighten(amount)- Lighten by percentageinterpolate(other, t)- Mix two colors (t=0.0 to 1.0)
- Multiple output formats:
toHex(includeAlpha)- Hex string representationtoRgb()- RGB/RGBA stringtoHsl()- HSL/HSLA stringtoString()- SVG-compatible format (hex for opaque, rgba for transparent)
- 147 named SVG colors: All standard SVG color names (red, blue, crimson, etc.)
- Type safety: Proper value clamping, equals/hashCode support
Quick Wins
hasAttribute(name): Check if an SVG attribute exists on an elementattrs(map): Convenient alias foraddAttributes(map)for batch attribute setting
Debugging
toString()implementation: Added toString() for all SVG elements showing element name, attributes, and parent information for easier debugging
Tests
- Added 45 new tests (12 transform tests, 30 color tests, 3 utility tests)
- Total test count: 303 tests (all passing)
- Comprehensive coverage of new utilities
Ver 0.5.0
- Merging: new
SvgMergerutility to merge SVGs horizontally, vertically, or layered on top using pure object-oriented copying (no XML serialization). - Cloning support: added
SvgElementFactoryand adopting constructors across all SVG element types to enable deep copies that preserve DOM and children lists. - API ergonomics:
SvgElement.clone(AbstractElementContainer)for deep cloning of element trees. - Documentation: new
doc/merging.md, updateddoc/overview.md, and comprehensive sprint summaries. - Tests: added
SvgMergerTestandSvgElementFactoryTestfor merge/copy behavior and coverage. - Build cleanup: upgraded JUnit, JaCoCo, and central-publishing plugins; removed legacy Gradle artifacts.
API additions/updates
SvgMerger.mergeHorizontally,SvgMerger.mergeVertically,SvgMerger.mergeOnTop.SvgElementFactory.fromElement,SvgElementFactory.deepCopy,SvgElementFactory.copyChildren.SvgElement.clone(AbstractElementContainer)deep clone helper.
Ver 0.4.0
- API ergonomics: property-style attribute access on SvgElement, addAttributes(Map), and Map-based addX(Map) helpers across element containers (filters, gradients, defs, text, etc.).
- Attribute coverage: expanded fluent setters/getters across shapes, text, gradients, filters, and animation elements (Phase 1-3 convenience methods).
- Animation/text improvements: more complete Animate/AnimateMotion/AnimateTransform/Set attribute helpers plus additional Text/Tspan/TextPath conveniences.
- Bug fixes: AbstractPoly.addPoint() and addPoints() now handle missing points attributes correctly.
- Build & tests: @CompileStatic across core classes, JaCoCo coverage reporting, Gradle wrapper removal, and expanded unit tests (filters, gradients, text, shapes, script/switch, polygon/polyline).
API additions/updates
- Property-style attribute read/write fallback when no explicit getter/setter exists.
- Map-based attributes in element factory methods (for example, addRect([x: 1, y: 2])) plus addAttributes(Map).
- Additional attribute setters for gradients, stops (stop-opacity), filter primitives, and text positioning/typography.
Ver 0.3.0
- Documentation overhaul: new docs in doc/creating.md, doc/parsing.md, and doc/overview.md, plus expanded Groovydoc across the public API and readme tweaks.
- API ergonomics: added many String overloads for numeric SVG attributes to allow unit/percent values across shapes, text, filters, patterns, markers, symbols, and foreignObject; plus new paint helpers
(dash array/offset, opacity, miterlimit) on shapes. - Build fix: Maven sources JAR now includes Groovy sources (build-helper source roots + source plugin includes).
- Test coverage: added tests for parsing docs examples and expanded filter/FeComposite coverage.
API additions/updates
- New convenience setters for SVG attributes across shapes and filters (String overloads for unit/percent values).
- Additional stroke/fill presentation helpers on shapes (dasharray/dashoffset, opacity, miterlimit).
- Animation and filter helper extensions (e.g., String overloads for from/k1‑k4, etc.).
Ver 0.2.0
- Security/Parsing
- Hardened SAX parser against XXE/DTD and enabled secure processing in SvgReader (prevents external entity resolution).
- Improved element dispatch for prefixed SVG tags and nested handling; namespace declarations now captured before attribute parsing and foreign/default namespaces preserved (e.g. foreignObject/metadata).
- Safer QName handling and null-safe attribute removal in SvgElement.
- SVG 1.1 / SVG 2 Coverage
- Added missing elements: color-profile, cursor, solidcolor, mesh gradients (meshGradient, mesh, meshrow, meshpatch), hatching (hatch, hatchpath), media (audio, video), discard, and font module elements (font, font-face*, glyph, missing-glyph, hkern, vkern, glyphRef, altGlyph*, tref).
- Added href parity for SVG2: use, image, mpath, feImage, textPath, script accept href with xlink fallback; getters normalized.
- Attribute/API Enhancements
- Gradients gain gradientTransform and spreadMethod; filters gain colour-interpolation-filters and filterRes.
- Markers add markerUnits and orient.
- Shapes add fill-rule, stroke-linejoin, stroke-linecap.
- Text adds baseline-shift, dominant-baseline, text-decoration, word-spacing, letter-spacing.
- Fluent chaining fixed across new setters; Use.getHref() aligned with other elements.
- Build & Publishing
- Removed Gradle and added Maven POM with SCM, license, developer, and OSSRH distribution metadata; Groovy groupId corrected to org.apache.groovy.
- Dependency updates and documentation tweaks.
- Tests
- New regression tests for security (XXE block), namespace preservation, href support, and new element parsing;