feat(ast,ipub): remove marshalling and unmarshalling logic from ast
This commit is contained in:
224
ipub/ast/ast.go
224
ipub/ast/ast.go
@@ -1,95 +1,87 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Element interface {
|
type Node interface {
|
||||||
Name() ElementName
|
Kind() NodeKind
|
||||||
Kind() ElementKind
|
|
||||||
|
|
||||||
NextSibling() Element
|
NextSibling() Node
|
||||||
SetNextSibling(Element)
|
SetNextSibling(Node)
|
||||||
|
|
||||||
PreviousSibling() Element
|
PreviousSibling() Node
|
||||||
SetPreviousSibling(Element)
|
SetPreviousSibling(Node)
|
||||||
|
|
||||||
Parent() Element
|
Parent() Node
|
||||||
SetParent(Element)
|
SetParent(Node)
|
||||||
|
|
||||||
HasChildren() bool
|
HasChildren() bool
|
||||||
ChildCount() uint
|
ChildCount() uint
|
||||||
|
|
||||||
FirstChild() Element
|
FirstChild() Node
|
||||||
LastChild() Element
|
LastChild() Node
|
||||||
|
|
||||||
AppendChild(self, v Element)
|
AppendChild(self, v Node)
|
||||||
RemoveChild(self, v Element)
|
RemoveChild(self, v Node)
|
||||||
|
|
||||||
RemoveChildren(self Element)
|
RemoveChildren(self Node)
|
||||||
ReplaceChild(self, v1, insertee Element)
|
ReplaceChild(self, v1, insertee Node)
|
||||||
|
|
||||||
InsertBefore(self, v1, insertee Element)
|
InsertBefore(self, v1, insertee Node)
|
||||||
InsertAfter(self, v1, insertee Element)
|
InsertAfter(self, v1, insertee Node)
|
||||||
|
|
||||||
xml.Marshaler
|
|
||||||
xml.Unmarshaler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseElement struct {
|
type BaseNode struct {
|
||||||
next Element
|
next Node
|
||||||
prev Element
|
prev Node
|
||||||
parent Element
|
parent Node
|
||||||
fisrtChild Element
|
fisrtChild Node
|
||||||
lastChild Element
|
lastChild Node
|
||||||
childCount uint
|
childCount uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) NextSibling() Element {
|
func (e *BaseNode) NextSibling() Node {
|
||||||
return e.next
|
return e.next
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) SetNextSibling(v Element) {
|
func (e *BaseNode) SetNextSibling(v Node) {
|
||||||
e.next = v
|
e.next = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) PreviousSibling() Element {
|
func (e *BaseNode) PreviousSibling() Node {
|
||||||
return e.prev
|
return e.prev
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) SetPreviousSibling(v Element) {
|
func (e *BaseNode) SetPreviousSibling(v Node) {
|
||||||
e.prev = v
|
e.prev = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) Parent() Element {
|
func (e *BaseNode) Parent() Node {
|
||||||
return e.parent
|
return e.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) SetParent(v Element) {
|
func (e *BaseNode) SetParent(v Node) {
|
||||||
e.parent = v
|
e.parent = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) HasChildren() bool {
|
func (e *BaseNode) HasChildren() bool {
|
||||||
return e.fisrtChild != nil
|
return e.fisrtChild != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) ChildCount() uint {
|
func (e *BaseNode) ChildCount() uint {
|
||||||
return e.childCount
|
return e.childCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) FirstChild() Element {
|
func (e *BaseNode) FirstChild() Node {
|
||||||
return e.fisrtChild
|
return e.fisrtChild
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) LastChild() Element {
|
func (e *BaseNode) LastChild() Node {
|
||||||
return e.lastChild
|
return e.lastChild
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) AppendChild(self, v Element) {
|
func (e *BaseNode) AppendChild(self, v Node) {
|
||||||
ensureIsolated(v)
|
ensureIsolated(v)
|
||||||
|
|
||||||
if e.fisrtChild == nil {
|
if e.fisrtChild == nil {
|
||||||
@@ -107,7 +99,7 @@ func (e *BaseElement) AppendChild(self, v Element) {
|
|||||||
e.childCount++
|
e.childCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) RemoveChild(self, v Element) {
|
func (e *BaseNode) RemoveChild(self, v Node) {
|
||||||
if v.Parent() != self {
|
if v.Parent() != self {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -136,7 +128,7 @@ func (e *BaseElement) RemoveChild(self, v Element) {
|
|||||||
v.SetPreviousSibling(nil)
|
v.SetPreviousSibling(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) RemoveChildren(_ Element) {
|
func (e *BaseNode) RemoveChildren(_ Node) {
|
||||||
for c := e.fisrtChild; c != nil; {
|
for c := e.fisrtChild; c != nil; {
|
||||||
c.SetParent(nil)
|
c.SetParent(nil)
|
||||||
c.SetPreviousSibling(nil)
|
c.SetPreviousSibling(nil)
|
||||||
@@ -149,16 +141,16 @@ func (e *BaseElement) RemoveChildren(_ Element) {
|
|||||||
e.childCount = 0
|
e.childCount = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) ReplaceChild(self, v1, insertee Element) {
|
func (e *BaseNode) ReplaceChild(self, v1, insertee Node) {
|
||||||
e.InsertBefore(self, v1, insertee)
|
e.InsertBefore(self, v1, insertee)
|
||||||
e.RemoveChild(self, v1)
|
e.RemoveChild(self, v1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) InsertAfter(self, v1, insertee Element) {
|
func (e *BaseNode) InsertAfter(self, v1, insertee Node) {
|
||||||
e.InsertBefore(self, v1.NextSibling(), insertee)
|
e.InsertBefore(self, v1.NextSibling(), insertee)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) InsertBefore(self, v1, insertee Element) {
|
func (e *BaseNode) InsertBefore(self, v1, insertee Node) {
|
||||||
e.childCount++
|
e.childCount++
|
||||||
if v1 == nil {
|
if v1 == nil {
|
||||||
e.AppendChild(self, insertee)
|
e.AppendChild(self, insertee)
|
||||||
@@ -183,149 +175,21 @@ func (e *BaseElement) InsertBefore(self, v1, insertee Element) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *BaseElement) UnmarshalXMLElement(self Element, d *xml.Decoder, start xml.StartElement) error {
|
func ensureIsolated(e Node) {
|
||||||
elErr := fmt.Errorf("unable to unmarshal element kind %q", self.Kind())
|
|
||||||
|
|
||||||
if n := self.Name(); n != (xml.Name{}) {
|
|
||||||
if n != start.Name {
|
|
||||||
return errors.Join(
|
|
||||||
elErr,
|
|
||||||
fmt.Errorf("element has different name (%q) than expected (%q)",
|
|
||||||
fmtXMLName(start.Name), fmtXMLName(n)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
token, err := d.Token()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err == io.EOF {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tt := token.(type) {
|
|
||||||
case xml.StartElement:
|
|
||||||
elErr = errors.Join(elErr, fmt.Errorf("unable to unmarshal child element %q", fmtXMLName(tt.Name)))
|
|
||||||
|
|
||||||
i := slices.IndexFunc(tt.Attr, func(a xml.Attr) bool {
|
|
||||||
return a.Name == elementKindAttrName
|
|
||||||
})
|
|
||||||
if i == -1 {
|
|
||||||
return errors.Join(elErr, fmt.Errorf("element kind not specified"))
|
|
||||||
}
|
|
||||||
|
|
||||||
var k ElementKind
|
|
||||||
if err := k.UnmarshalXMLAttr(tt.Attr[i]); err != nil {
|
|
||||||
return errors.Join(elErr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c := k.Element()
|
|
||||||
|
|
||||||
err := d.DecodeElement(c, &tt)
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
e.AppendChild(self, c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *BaseElement) MarshalXMLElement(self Element, enc *xml.Encoder, start xml.StartElement) error {
|
|
||||||
elErr := fmt.Errorf("unable to marshal element kind %q", self.Kind())
|
|
||||||
|
|
||||||
if n := self.Name(); n != (xml.Name{}) {
|
|
||||||
start.Name = self.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
ka, err := self.Kind().MarshalXMLAttr(elementKindAttrName)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Join(elErr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
start.Attr = append(start.Attr, ka)
|
|
||||||
|
|
||||||
data := struct {
|
|
||||||
Children []Element `xml:",any"`
|
|
||||||
}{Children: []Element{}}
|
|
||||||
|
|
||||||
for c := self.FirstChild(); c != nil; {
|
|
||||||
data.Children = append(data.Children, c)
|
|
||||||
c = c.NextSibling()
|
|
||||||
}
|
|
||||||
|
|
||||||
err = enc.EncodeElement(&data, start)
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
return err
|
|
||||||
return errors.Join(elErr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureIsolated(e Element) {
|
|
||||||
if p := e.Parent(); p != nil {
|
if p := e.Parent(); p != nil {
|
||||||
p.RemoveChild(p, e)
|
p.RemoveChild(p, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type NodeKind string
|
||||||
ElementName = xml.Name
|
|
||||||
ElementKind string
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewElementKind(kind string, e Element) ElementKind {
|
func NewNodeKind(kind string, e Node) NodeKind {
|
||||||
k := ElementKind(kind)
|
k := NodeKind(kind)
|
||||||
if _, ok := elementKindList[k]; ok {
|
if _, ok := elementKindList[k]; ok {
|
||||||
panic(fmt.Sprintf("Element kind %q is already registered", k))
|
panic(fmt.Sprintf("Node kind %q is already registered", k))
|
||||||
}
|
}
|
||||||
elementKindList[k] = e
|
elementKindList[k] = e
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var elementKindList = make(map[NodeKind]Node)
|
||||||
_ xml.MarshalerAttr = ElementKind("")
|
|
||||||
_ xml.UnmarshalerAttr = (*ElementKind)(nil)
|
|
||||||
_ fmt.Stringer = ElementKind("")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (k ElementKind) MarshalXMLAttr(n xml.Name) (xml.Attr, error) {
|
|
||||||
if n != elementKindAttrName {
|
|
||||||
return xml.Attr{}, ErrInvalidAttrName{Actual: n, Expected: elementKindAttrName}
|
|
||||||
}
|
|
||||||
|
|
||||||
return xml.Attr{
|
|
||||||
Name: elementKindAttrName,
|
|
||||||
Value: k.String(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *ElementKind) UnmarshalXMLAttr(attr xml.Attr) error {
|
|
||||||
if attr.Name != elementKindAttrName {
|
|
||||||
return ErrInvalidAttrName{Actual: attr.Name, Expected: elementKindAttrName}
|
|
||||||
}
|
|
||||||
|
|
||||||
ak := ElementKind(attr.Value)
|
|
||||||
if _, ok := elementKindList[ak]; !ok {
|
|
||||||
return ErrInvalidAttrValue{Attr: attr, Message: "element kind not registered"}
|
|
||||||
}
|
|
||||||
|
|
||||||
*k = ak
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k ElementKind) String() string {
|
|
||||||
return string(k)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k ElementKind) Element() Element {
|
|
||||||
return elementKindList[k]
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
elementKindList = make(map[ElementKind]Element)
|
|
||||||
elementKindAttrName = xml.Name{Local: "data-ipub-element"}
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,68 +1,27 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/xml"
|
|
||||||
"slices"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Content struct {
|
type Content struct {
|
||||||
BaseElement
|
BaseNode
|
||||||
}
|
}
|
||||||
|
|
||||||
var KindContent = NewElementKind("content", &Content{})
|
var KindContent = NewNodeKind("content", &Content{})
|
||||||
|
|
||||||
func (e Content) Name() ElementName {
|
func (e Content) Kind() NodeKind {
|
||||||
return ElementName{Local: "section"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Content) Kind() ElementKind {
|
|
||||||
return KindContent
|
return KindContent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Content) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
|
||||||
return e.MarshalXMLElement(e, enc, start)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Content) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
|
|
||||||
return e.UnmarshalXMLElement(e, dec, start)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Image struct {
|
type Image struct {
|
||||||
src string
|
src string
|
||||||
|
|
||||||
BaseElement
|
BaseNode
|
||||||
}
|
}
|
||||||
|
|
||||||
var KindImage = NewElementKind("image", &Image{})
|
var KindImage = NewNodeKind("image", &Image{})
|
||||||
|
|
||||||
func (e *Image) Name() ElementName {
|
func (e *Image) Kind() NodeKind {
|
||||||
return ElementName{Local: "img"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Image) Kind() ElementKind {
|
|
||||||
return KindImage
|
return KindImage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Image) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
|
||||||
if src := e.Source(); src != "" {
|
|
||||||
start.Attr = append(start.Attr, xml.Attr{
|
|
||||||
Name: xml.Name{Local: "src"},
|
|
||||||
Value: src,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return e.MarshalXMLElement(e, enc, start)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Image) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
|
|
||||||
i := slices.IndexFunc(start.Attr, func(a xml.Attr) bool {
|
|
||||||
return a.Name == xml.Name{Local: "src"}
|
|
||||||
})
|
|
||||||
if i > -1 {
|
|
||||||
e.SetSource(start.Attr[i].Value)
|
|
||||||
}
|
|
||||||
return e.UnmarshalXMLElement(e, dec, start)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Image) Source() string {
|
func (e Image) Source() string {
|
||||||
return e.src
|
return e.src
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
package ast
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/xml"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ErrInvalidAttrName struct {
|
|
||||||
Actual xml.Name
|
|
||||||
Expected xml.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ error = ErrInvalidAttrName{}
|
|
||||||
|
|
||||||
func (err ErrInvalidAttrName) Error() string {
|
|
||||||
return fmt.Sprintf("attribute %q has invalid name, expected %q", fmtXMLName(err.Expected), fmtXMLName(err.Actual))
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrInvalidAttrValue struct {
|
|
||||||
Attr xml.Attr
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ error = ErrInvalidAttrValue{}
|
|
||||||
|
|
||||||
func (err ErrInvalidAttrValue) Error() string {
|
|
||||||
return fmt.Sprintf("attribute %q's value %q is invalid: %s", fmtXMLName(err.Attr.Name), err.Attr.Value, err.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fmtXMLName(n xml.Name) string {
|
|
||||||
s := n.Local
|
|
||||||
if n.Space != "" {
|
|
||||||
s = fmt.Sprintf("%s:%s", n.Space, n.Local)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
11
ipub/ast/package.go
Normal file
11
ipub/ast/package.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
type Package struct {
|
||||||
|
BaseNode
|
||||||
|
}
|
||||||
|
|
||||||
|
var KindPackage = NewNodeKind("package", &Package{})
|
||||||
|
|
||||||
|
func (e Package) Kind() NodeKind {
|
||||||
|
return KindPackage
|
||||||
|
}
|
||||||
@@ -10,23 +10,11 @@ type Section struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Body struct {
|
type Body struct {
|
||||||
BaseElement
|
BaseNode
|
||||||
}
|
}
|
||||||
|
|
||||||
var KindBody = NewElementKind("body", &Body{})
|
var KindBody = NewNodeKind("body", &Body{})
|
||||||
|
|
||||||
func (e Body) Name() ElementName {
|
func (e Body) Kind() NodeKind {
|
||||||
return ElementName{Local: "body"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Body) Kind() ElementKind {
|
|
||||||
return KindBody
|
return KindBody
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Body) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
|
||||||
return e.MarshalXMLElement(e, enc, start)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Body) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
|
|
||||||
return e.UnmarshalXMLElement(e, dec, start)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user