package svg
import (
"strings"
)
type Node interface {
appendXML(*strings .Builder )
}
type Attribute struct {
Name string
Value string
}
type Style struct {
Name string
Value string
}
type Element struct {
Tag string
Attributes []Attribute
Styles []Style
Children []Node
stylesAfterAttributes bool
}
func NewElement (tag string , children ...Node ) *Element {
return &Element {Tag : tag , Children : append ([]Node (nil ), children ...)}
}
func (e *Element ) SetAttr (name , value string ) *Element {
for i := range e .Attributes {
if e .Attributes [i ].Name == name {
e .Attributes [i ].Value = value
return e
}
}
e .Attributes = append (e .Attributes , Attribute {Name : name , Value : value })
return e
}
func (e *Element ) RemoveAttr (name string ) bool {
for i := range e .Attributes {
if e .Attributes [i ].Name == name {
copy (e .Attributes [i :], e .Attributes [i +1 :])
e .Attributes = e .Attributes [:len (e .Attributes )-1 ]
return true
}
}
return false
}
func (e *Element ) SetStyle (name , value string ) *Element {
for i := range e .Styles {
if e .Styles [i ].Name == name {
e .Styles [i ].Value = value
return e
}
}
e .Styles = append (e .Styles , Style {Name : name , Value : value })
return e
}
func (e *Element ) StylesAfterAttributes () *Element {
e .stylesAfterAttributes = true
return e
}
func (e *Element ) Append (children ...Node ) *Element {
e .Children = append (e .Children , children ...)
return e
}
func (e *Element ) Prepend (children ...Node ) *Element {
all := make ([]Node , 0 , len (children )+len (e .Children ))
all = append (all , children ...)
all = append (all , e .Children ...)
e .Children = all
return e
}
type Text string
func (t Text ) appendXML (builder *strings .Builder ) { escapeText (builder , string (t )) }
func (e *Element ) appendXML (builder *strings .Builder ) {
builder .WriteByte ('<' )
builder .WriteString (e .Tag )
if !e .stylesAfterAttributes {
e .appendStyle (builder )
}
for _ , attribute := range e .Attributes {
builder .WriteByte (' ' )
builder .WriteString (attribute .Name )
builder .WriteString (`="` )
escapeAttribute (builder , attribute .Value )
builder .WriteByte ('"' )
}
if e .stylesAfterAttributes {
e .appendStyle (builder )
}
builder .WriteByte ('>' )
for _ , child := range e .Children {
if child != nil {
child .appendXML (builder )
}
}
builder .WriteString ("</" )
builder .WriteString (e .Tag )
builder .WriteByte ('>' )
}
func (e *Element ) appendStyle (builder *strings .Builder ) {
if len (e .Styles ) == 0 {
return
}
builder .WriteString (` style="` )
for i , style := range e .Styles {
if i != 0 {
builder .WriteByte (' ' )
}
builder .WriteString (style .Name )
builder .WriteString (": " )
escapeAttribute (builder , style .Value )
builder .WriteByte (';' )
}
builder .WriteByte ('"' )
}
func (e *Element ) String () string {
var builder strings .Builder
e .appendXML (&builder )
return builder .String ()
}
func escapeText(builder *strings .Builder , value string ) {
for _ , r := range value {
switch r {
case '&' :
builder .WriteString ("&" )
case '<' :
builder .WriteString ("<" )
case '>' :
builder .WriteString (">" )
default :
builder .WriteRune (r )
}
}
}
func escapeAttribute(builder *strings .Builder , value string ) {
for _ , r := range value {
switch r {
case '&' :
builder .WriteString ("&" )
case '"' :
builder .WriteString (""" )
case '<' :
builder .WriteString ("<" )
case '>' :
builder .WriteString (">" )
default :
builder .WriteRune (r )
}
}
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .