Compare commits

..

9 Commits
v0.5.0 ... main

20 changed files with 414 additions and 182 deletions

269
README.md
View File

@ -2,7 +2,7 @@
An extensible Atom feed generator library that aims to be very close to RFC4287. An extensible Atom feed generator library that aims to be very close to RFC4287.
It diligently checks for compliance with the standard and provides functions for It diligently checks for compliance with the standard and provides functions for
easy creation and extension of elements. easy creation, extension and deletion of elements.
## Installation ## Installation
@ -14,45 +14,47 @@ go get git.streifling.com/jason/atom@latest
## Usage ## Usage
This library provides convenient functions to safely create and extend elements ### Basic Feed
and attributes of Atom feeds. It also provides checks for all constructs'
adherence to RFC4287. This library provides convenient functions to safely create, extend and delete
elements and attributes of Atom feeds. It also provides checks for all
constructs' adherence to RFC4287.
```go ```go
package main package main
import ( import (
"fmt" "fmt"
"log" "log"
"git.streifling.com/jason/atom" "git.streifling.com/jason/atom"
) )
func main() { func main() {
feed := atom.NewFeed("Example Feed") feed := atom.NewFeed("Example Feed")
if err := feed.Check(); err != nil { if err := feed.Check(); err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
author := atom.NewPerson("John Doe") author := atom.NewPerson("John Doe")
author.Email = "john.doe@example.com" author.Email = "john.doe@example.com"
if err := author.Check(); err != nil { if err := author.Check(); err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
feed.AddAuthor(author) feed.AddAuthor(author)
entry := atom.NewEntry("First Entry") entry := atom.NewEntry("First Entry")
entry.Content = atom.NewContent(atom.InlineText, "text", "This is the content of the first entry.") entry.Content = atom.NewContent(atom.InlineText, "text", "This is the content of the first entry.")
if err := entry.Check(); err != nil { if err := entry.Check(); err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
feed.AddEntry(entry) feed.AddEntry(entry)
feedString, err := feed.ToXML("utf-8") feedString, err := feed.ToXML("UTF-8")
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
fmt.Println(feedString) fmt.Println(feedString)
} }
``` ```
@ -63,70 +65,177 @@ provide.
package main package main
import ( import (
"fmt" "fmt"
"log" "log"
"time" "time"
"git.streifling.com/jason/atom" "git.streifling.com/jason/atom"
"github.com/google/uuid"
) )
func main() { func main() {
now := time.Now() now := time.Now()
feed := &atom.Feed{ feed := &atom.Feed{
Title: &atom.PlainText{ Title: &atom.PlainText{
Type: "text", Type: "text",
Text: "Example Feed", Text: "Example Feed",
}, },
ID: &atom.ID{URI: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6"}, ID: &atom.ID{URI: fmt.Sprint("urn:uuid:", uuid.New())},
Updated: &atom.Date{DateTime: atom.DateTime(now)}, Updated: &atom.Date{DateTime: atom.DateTime(now)},
Authors: []*atom.Person{ Authors: []*atom.Person{
{ {
Name: "John Doe", Name: "John Doe",
Email: "john.doe@example.com", Email: "john.doe@example.com",
}, },
}, },
Entries: []*atom.Entry{ Entries: []*atom.Entry{
{ {
Title: &atom.PlainText{ Title: &atom.PlainText{
Type: "text", Type: "text",
Text: "First Entry", Text: "First Entry",
}, },
ID: &atom.ID{URI: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a"}, ID: &atom.ID{URI: fmt.Sprint("urn:uuid:", uuid.New())},
Updated: &atom.Date{DateTime: atom.DateTime(now)}, Updated: &atom.Date{DateTime: atom.DateTime(now)},
Content: &atom.InlineTextContent{ Content: &atom.InlineTextContent{
Type: "text", Type: "text",
Text: "This is the content of the first entry.", Text: "This is the content of the first entry.",
}, },
}, },
}, },
} }
feedString, err := feed.ToXML("utf-8") feedString, err := feed.ToXML("UTF-8")
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
fmt.Println(feedString) fmt.Println(feedString)
} }
``` ```
The output of both ways of using it is an RFC4287 compliant Atom feed. The output of both ways of using it is an RFC4287 compliant Atom feed.
```xml ```xml
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<author> <author>
<name>John Doe</name> <name>John Doe</name>
<email>john.doe@example.com</email> <email>john.doe@example.com</email>
</author> </author>
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id> <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
<title type="text">Example Feed</title> <title type="text">Example Feed</title>
<updated>2024-10-18T05:49:08+02:00</updated> <updated>2024-10-18T05:49:08+02:00</updated>
<entry> <entry>
<content type="text">This is the content of the first entry.</content> <content type="text">This is the content of the first entry.</content>
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id> <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<title type="text">First Entry</title> <title type="text">First Entry</title>
<updated>2006-01-02T15:04:05+07:00</updated> <updated>2006-01-02T15:04:05+07:00</updated>
</entry> </entry>
</feed>
```
### Compliance and Error Checking
All Atom constructs have their own ```construct.Check()``` method. It checks for
compliance with RFC4287 and errors. This allows one to be certain that only
compliant constructs are added to their respective parent construct. It also
means that not the entire feed has to be checked every time a new construct is
added. Instead one only checks the current construct and all of its
sub-constructs with a single ```construct.Check()``` call.
```go
package main
import (
"fmt"
"log"
"git.streifling.com/jason/atom"
)
func main() {
feed := atom.NewFeed("Example Feed")
if err := feed.Check(); err != nil {
log.Fatalln(err)
}
entry := atom.NewEntry("One")
entry.Content = atom.NewContent(atom.InlineText, "text", "Entry One")
entry.AddAuthor(atom.NewPerson("John Doe"))
if err := entry.Check(); err != nil {
log.Fatalln(err)
}
feed.AddEntry(entry)
feedString, err := feed.ToXML("UTF-8")
if err != nil {
log.Fatalln(err)
}
fmt.Println(feedString)
}
```
### Adding and Deleting Items
To add elements to any slice one calls the appropriate
```someone.AddSomething(toBeAdded)``` method. It returns the item's index
number. To delete the item one calls the Delete method.
```go
package main
import (
"fmt"
"log"
"git.streifling.com/jason/atom"
)
func main() {
feed := atom.NewFeed("Feed")
if err := feed.Check(); err != nil {
log.Fatalln(err)
}
e1 := atom.NewEntry("One")
e1.Content = atom.NewContent(atom.InlineText, "text", "Entry One")
if err := e1.Check(); err != nil {
log.Fatalln(err)
}
i1 := feed.AddEntry(e1)
e2 := atom.NewEntry("Two")
e2.Content = atom.NewContent(atom.InlineText, "text", "Entry Two")
if err := e2.Check(); err != nil {
log.Fatalln(err)
}
feed.AddEntry(e2)
if err := feed.DeleteEntry(i1); err != nil {
log.Fatalln(err)
}
feedString, err := feed.ToXML("UTF-8")
if err != nil {
log.Fatalln(err)
}
fmt.Println(feedString)
}
```
The output of this example looks like this. It only shows the second entry.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>urn:uuid:ae89d343-b535-447d-ac14-4b80d3e02a2f</id>
<title type="text">Example Feed</title>
<updated>2024-10-20T14:57:02+02:00</updated>
<entry>
<content type="text">Entry Two</content>
<id>urn:uuid:620c6f73-ee1d-4c1e-be98-b0b1ad7a053f</id>
<title type="text">Two</title>
<updated>2024-10-20T14:57:02+02:00</updated>
</entry>
</feed> </feed>
``` ```

View File

@ -16,12 +16,14 @@ type Countable interface {
*xml.Attr | *Person | *Category | *Link | *ExtensionElement | *Entry *xml.Attr | *Person | *Category | *Link | *ExtensionElement | *Entry
} }
// addToSlice adds a Countable to to a *[]Countable // addToSlice adds a Countable to to a *[]Countable. It returns an int.
func addToSlice[C Countable](slice *[]C, countable C) { func addToSlice[C Countable](slice *[]C, countable C) int {
if *slice == nil { if *slice == nil {
*slice = make([]C, 0) *slice = make([]C, 0)
} }
*slice = append(*slice, countable) *slice = append(*slice, countable)
return len(*slice) - 1
} }
// deleteFromSlice deletes the Countable with the index from the *[]Countable. // deleteFromSlice deletes the Countable with the index from the *[]Countable.

View File

@ -10,22 +10,17 @@ type Category struct {
*CommonAttributes *CommonAttributes
Term string `xml:"term,attr"` Term string `xml:"term,attr"`
Scheme string `xml:"scheme,attr,omitempty"` // IRI Scheme string `xml:"scheme,attr,omitempty"` // IRI
Label string `xml:"label,attr,omitempty"` Label string `xml:"label,attr,omitempty"` // Must be unescaped
} }
// NewCategory creates a new Category. It returns a *Category. // NewCategory creates a new Category. It returns a *Category.
func NewCategory(term string) *Category { func NewCategory(term string) *Category {
return &Category{ return &Category{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Term: term, Term: term,
} }
} }
// SetLabel sets the Label attribute of the Category.
func (c *Category) SetLabel(label string) {
c.Label = Unescape(label)
}
// Check checks the Category for incompatibilities with RFC4287. It returns an // Check checks the Category for incompatibilities with RFC4287. It returns an
// error. // error.
func (c *Category) Check() error { func (c *Category) Check() error {

View File

@ -13,13 +13,14 @@ type CommonAttributes struct {
// NewCommonAttributes creates a new set of CommonAttributes. It returns a // NewCommonAttributes creates a new set of CommonAttributes. It returns a
// *CommonAttributes. // *CommonAttributes.
func newCommonAttributes() *CommonAttributes { func NewCommonAttributes() *CommonAttributes {
return new(CommonAttributes) return new(CommonAttributes)
} }
// AddAttribute adds the attribute to the CommonAttributes. // AddAttribute adds the attribute to the CommonAttributes. It returns its index
func (c *CommonAttributes) AddAttribute(name, value string) { // as an int.
addToSlice(&c.UndefinedAttributes, &xml.Attr{Name: xml.Name{Local: name}, Value: value}) func (c *CommonAttributes) AddAttribute(name, value string) int {
return addToSlice(&c.UndefinedAttributes, &xml.Attr{Name: xml.Name{Local: name}, Value: value})
} }
// DeleteAttribute deletes the attribute at index from the CommonAttributes. It // DeleteAttribute deletes the attribute at index from the CommonAttributes. It

View File

@ -19,7 +19,7 @@ func DateTime(t time.Time) string {
// NewDate creates a new Date. It returns a *Date. // NewDate creates a new Date. It returns a *Date.
func NewDate(t time.Time) *Date { func NewDate(t time.Time) *Date {
return &Date{ return &Date{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
DateTime: DateTime(t), DateTime: DateTime(t),
} }
} }

105
entry.go
View File

@ -59,17 +59,23 @@ func (e *Entry) checkAuthors(authorInFeed bool) error {
// NewEntry creates a new Entry. It returns a *Entry. // NewEntry creates a new Entry. It returns a *Entry.
func NewEntry(title string) *Entry { func NewEntry(title string) *Entry {
return &Entry{ return &Entry{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
ID: NewID(NewURN()), ID: NewID(NewURN()),
Title: NewText("text", title), Title: NewText("text", title),
Updated: NewDate(time.Now()), Updated: NewDate(time.Now()),
} }
} }
// AddAuthor adds the Person as an author to the Entry. // AddAuthor adds the Person as an author to the Entry. It returns its index as
func (e *Entry) AddAuthor(p *Person) { // an int.
addToSlice(&e.Authors, p) func (e *Entry) AddAuthor(p *Person) int {
e.Updated = NewDate(time.Now()) if e.Updated == nil {
e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&e.Authors, p)
} }
// DeleteAuthor deletes the Person at index from the Entry. It return an error. // DeleteAuthor deletes the Person at index from the Entry. It return an error.
@ -78,14 +84,24 @@ func (e *Entry) DeleteAuthor(index int) error {
return fmt.Errorf("error deleting author %v from entry %v: %v", index, e.ID.URI, err) return fmt.Errorf("error deleting author %v from entry %v: %v", index, e.ID.URI, err)
} }
e.Updated = NewDate(time.Now()) if e.Updated == nil {
e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
// AddCategory adds the Category to the Entry. // AddCategory adds the Category to the Entry. It returns ts index as an int.
func (e *Entry) AddCategory(c *Category) { func (e *Entry) AddCategory(c *Category) int {
addToSlice(&e.Categories, c) if e.Updated == nil {
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&e.Categories, c)
} }
// DeleteCategory deletes the Category at index from the Entry. It return an // DeleteCategory deletes the Category at index from the Entry. It return an
@ -95,14 +111,25 @@ func (e *Entry) DeleteCategory(index int) error {
return fmt.Errorf("error deleting category %v from entry %v: %v", index, e.ID.URI, err) return fmt.Errorf("error deleting category %v from entry %v: %v", index, e.ID.URI, err)
} }
e.Updated = NewDate(time.Now()) if e.Updated == nil {
e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
// AddContributor adds the Person as a contributor to the Entry. // AddContributor adds the Person as a contributor to the Entry. It returns its
func (e *Entry) AddContributor(c *Person) { // index as an int.
addToSlice(&e.Contributors, c) func (e *Entry) AddContributor(c *Person) int {
e.Updated = NewDate(time.Now()) if e.Updated == nil {
e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&e.Contributors, c)
} }
// DeleteContributor deletes the Person at index from the Entry. It return an // DeleteContributor deletes the Person at index from the Entry. It return an
@ -112,14 +139,24 @@ func (e *Entry) DeleteContributor(index int) error {
return fmt.Errorf("error deleting contributor %v from entry %v: %v", index, e.ID.URI, err) return fmt.Errorf("error deleting contributor %v from entry %v: %v", index, e.ID.URI, err)
} }
e.Updated = NewDate(time.Now()) if e.Updated == nil {
e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
// AddLink adds the Link to the Entry. // AddLink adds the Link to the Entry. It returns its index as an int.
func (e *Entry) AddLink(l *Link) { func (e *Entry) AddLink(l *Link) int {
addToSlice(&e.Links, l) if e.Updated == nil {
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&e.Links, l)
} }
// DeleteLink deletes the Link at index from the Entry. It return an error. // DeleteLink deletes the Link at index from the Entry. It return an error.
@ -128,14 +165,25 @@ func (e *Entry) DeleteLink(index int) error {
return fmt.Errorf("error deleting link %v from entry %v: %v", index, e.ID.URI, err) return fmt.Errorf("error deleting link %v from entry %v: %v", index, e.ID.URI, err)
} }
e.Updated = NewDate(time.Now()) if e.Updated == nil {
e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
// AddExtension adds the ExtensionElement to the Entry. // AddExtension adds the ExtensionElement to the Entry. It returns its index as
func (e *Entry) AddExtension(x *ExtensionElement) { // an int.
addToSlice(&e.Extensions, x) func (e *Entry) AddExtension(x *ExtensionElement) int {
e.Updated = NewDate(time.Now()) if e.Updated == nil {
e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&e.Extensions, x)
} }
// DeleteExtension deletes the Extension at index from the Entry. It return an // DeleteExtension deletes the Extension at index from the Entry. It return an
@ -145,7 +193,12 @@ func (e *Entry) DeleteExtension(index int) error {
return fmt.Errorf("error deleting extension %v from entry %v: %v", index, e.ID.URI, err) return fmt.Errorf("error deleting extension %v from entry %v: %v", index, e.ID.URI, err)
} }
e.Updated = NewDate(time.Now()) if e.Updated == nil {
e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }

130
feed.go
View File

@ -28,17 +28,23 @@ type Feed struct {
// NewFeed creates a new Feed. It returns a *Feed. // NewFeed creates a new Feed. It returns a *Feed.
func NewFeed(title string) *Feed { func NewFeed(title string) *Feed {
return &Feed{ return &Feed{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
ID: NewID(NewURN()), ID: NewID(NewURN()),
Title: NewText("text", title), Title: NewText("text", title),
Updated: NewDate(time.Now()), Updated: NewDate(time.Now()),
} }
} }
// AddAuthor adds the Person as an author to the Feed. // AddAuthor adds the Person as an author to the Feed. It returns its index as
func (f *Feed) AddAuthor(p *Person) { // an int.
addToSlice(&f.Authors, p) func (f *Feed) AddAuthor(p *Person) int {
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&f.Authors, p)
} }
// DeleteAuthor deletes the Person at index from the Feed. It return an error. // DeleteAuthor deletes the Person at index from the Feed. It return an error.
@ -47,14 +53,24 @@ func (f *Feed) DeleteAuthor(index int) error {
return fmt.Errorf("error deleting author %v from entry %v: %v", index, f.ID.URI, err) return fmt.Errorf("error deleting author %v from entry %v: %v", index, f.ID.URI, err)
} }
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
// AddCategory adds the Category to the Feed. // AddCategory adds the Category to the Feed. It returns its index as an int.
func (f *Feed) AddCategory(c *Category) { func (f *Feed) AddCategory(c *Category) int {
addToSlice(&f.Categories, c) if f.Updated == nil {
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&f.Categories, c)
} }
// DeleteCategory deletes the Category at index from the Feed. It return an // DeleteCategory deletes the Category at index from the Feed. It return an
@ -64,14 +80,25 @@ func (f *Feed) DeleteCategory(index int) error {
return fmt.Errorf("error deleting category %v from entry %v: %v", index, f.ID.URI, err) return fmt.Errorf("error deleting category %v from entry %v: %v", index, f.ID.URI, err)
} }
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
// AddContributor adds the Person as a contributor to the Feed. // AddContributor adds the Person as a contributor to the Feed. It returns its
func (f *Feed) AddContributor(c *Person) { // index as an int.
addToSlice(&f.Contributors, c) func (f *Feed) AddContributor(c *Person) int {
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&f.Contributors, c)
} }
// DeleteContributor deletes the Person at index from the Feed. It return an // DeleteContributor deletes the Person at index from the Feed. It return an
@ -81,14 +108,25 @@ func (f *Feed) DeleteContributor(index int) error {
return fmt.Errorf("error deleting contributor %v from entry %v: %v", index, f.ID.URI, err) return fmt.Errorf("error deleting contributor %v from entry %v: %v", index, f.ID.URI, err)
} }
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
// AddLink adds the Link to the Feed. There should be one Link with Rel "self". // AddLink adds the Link to the Feed. There should be one Link with Rel "self".
func (f *Feed) AddLink(l *Link) { // It returns its index as an int.
addToSlice(&f.Links, l) func (f *Feed) AddLink(l *Link) int {
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&f.Links, l)
} }
// DeleteLink deletes the Link at index from the Feed. It return an error. // DeleteLink deletes the Link at index from the Feed. It return an error.
@ -97,14 +135,24 @@ func (f *Feed) DeleteLink(index int) error {
return fmt.Errorf("error deleting link %v from entry %v: %v", index, f.ID.URI, err) return fmt.Errorf("error deleting link %v from entry %v: %v", index, f.ID.URI, err)
} }
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
// AddExtension adds the Extension to the Feed. // AddExtension adds the Extension to the Feed. It returns its index as an int.
func (f *Feed) AddExtension(e *ExtensionElement) { func (f *Feed) AddExtension(e *ExtensionElement) int {
addToSlice(&f.Extensions, e) if f.Updated == nil {
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&f.Extensions, e)
} }
// DeleteExtension deletes the Extension at index from the Feed. It return an // DeleteExtension deletes the Extension at index from the Feed. It return an
@ -114,14 +162,24 @@ func (f *Feed) DeleteExtension(index int) error {
return fmt.Errorf("error deleting extension %v from entry %v: %v", index, f.ID.URI, err) return fmt.Errorf("error deleting extension %v from entry %v: %v", index, f.ID.URI, err)
} }
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
// AddEntry adds the Entry to the Feed. // AddEntry adds the Entry to the Feed. It returns its index as an int.
func (f *Feed) AddEntry(e *Entry) { func (f *Feed) AddEntry(e *Entry) int {
addToSlice(&f.Entries, e) if f.Updated == nil {
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return addToSlice(&f.Entries, e)
} }
// DeleteEntry deletes the Entry at index from the Feed. It return an error. // DeleteEntry deletes the Entry at index from the Feed. It return an error.
@ -130,7 +188,12 @@ func (f *Feed) DeleteEntry(index int) error {
return fmt.Errorf("error deleting entry %v from entry %v: %v", index, f.ID.URI, err) return fmt.Errorf("error deleting entry %v from entry %v: %v", index, f.ID.URI, err)
} }
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }
@ -152,7 +215,12 @@ func (f *Feed) DeleteEntryByURI(uri string) error {
} }
f.Entries = append(f.Entries[:index], f.Entries[index+1:]...) f.Entries = append(f.Entries[:index], f.Entries[index+1:]...)
f.Updated = NewDate(time.Now()) if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
return nil return nil
} }

View File

@ -17,7 +17,7 @@ type Generator struct {
// NewGenerator creates a new Generator. It returns a *Generator. // NewGenerator creates a new Generator. It returns a *Generator.
func NewGenerator(text string) *Generator { func NewGenerator(text string) *Generator {
return &Generator{ return &Generator{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Text: html.UnescapeString(text), Text: html.UnescapeString(text),
} }
} }

View File

@ -15,7 +15,7 @@ type Icon struct {
// NewIcon creates a new Icon. It returns a *Icon. // NewIcon creates a new Icon. It returns a *Icon.
func NewIcon(uri string) *Icon { func NewIcon(uri string) *Icon {
return &Icon{ return &Icon{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
URI: uri, URI: uri,
} }
} }

2
id.go
View File

@ -15,7 +15,7 @@ type ID struct {
// NewID creates a new ID. It returns a *ID. // NewID creates a new ID. It returns a *ID.
func NewID(uri string) *ID { func NewID(uri string) *ID {
return &ID{ return &ID{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
URI: uri, URI: uri,
} }
} }

View File

@ -19,7 +19,7 @@ func newInlineOtherContent(mediaType string, content any) *InlineOtherContent {
mediaType, _, _ = mime.ParseMediaType(mediaType) mediaType, _, _ = mime.ParseMediaType(mediaType)
return &InlineOtherContent{ return &InlineOtherContent{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Type: mediaType, Type: mediaType,
AnyElement: content, AnyElement: content,
} }

View File

@ -16,7 +16,7 @@ type InlineTextContent struct {
// *InlineTextContent. // *InlineTextContent.
func newInlineTextContent(mediaType, text string) *InlineTextContent { func newInlineTextContent(mediaType, text string) *InlineTextContent {
return &InlineTextContent{ return &InlineTextContent{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Type: mediaType, Type: mediaType,
Text: text, Text: text,
} }

View File

@ -16,7 +16,7 @@ type InlineXHTMLContent struct {
// *InlineXHTMLContent. // *InlineXHTMLContent.
func newInlineXHTMLContent(mediaType string, div *XHTMLDiv) *InlineXHTMLContent { func newInlineXHTMLContent(mediaType string, div *XHTMLDiv) *InlineXHTMLContent {
return &InlineXHTMLContent{ return &InlineXHTMLContent{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Type: mediaType, Type: mediaType,
XHTMLDiv: div, XHTMLDiv: div,
} }

View File

@ -20,7 +20,7 @@ type Link struct {
// NewLink creates a new Link. It returns a *Link. // NewLink creates a new Link. It returns a *Link.
func NewLink(href string) *Link { func NewLink(href string) *Link {
return &Link{ return &Link{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Href: href, Href: href,
} }
} }

View File

@ -14,7 +14,7 @@ type Logo struct {
// NewLogo creates a new Logo. It returns a *Logo. // NewLogo creates a new Logo. It returns a *Logo.
func NewLogo(uri string) *Logo { func NewLogo(uri string) *Logo {
return &Logo{ return &Logo{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
URI: uri, URI: uri,
} }
} }

View File

@ -19,7 +19,7 @@ func newOutOfLineContent(mediaType, src string) *OutOfLineContent {
mediaType, _, _ = mime.ParseMediaType(mediaType) mediaType, _, _ = mime.ParseMediaType(mediaType)
return &OutOfLineContent{ return &OutOfLineContent{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Type: mediaType, Type: mediaType,
SRC: src, SRC: src,
} }

View File

@ -16,14 +16,15 @@ type Person struct {
// NewPerson creates a new Person. It returns a *Person. // NewPerson creates a new Person. It returns a *Person.
func NewPerson(name string) *Person { func NewPerson(name string) *Person {
return &Person{ return &Person{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Name: name, Name: name,
} }
} }
// AddExtension adds the Extension to the Person. // AddExtension adds the Extension to the Person. It returns its index as an
func (p *Person) AddExtension(e *ExtensionElement) { // int.
addToSlice(&p.Extensions, e) func (p *Person) AddExtension(e *ExtensionElement) int {
return addToSlice(&p.Extensions, e)
} }
// DeleteExtension deletes the Extension at index from the Person. It return an // DeleteExtension deletes the Extension at index from the Person. It return an

View File

@ -16,7 +16,7 @@ func (p *PlainText) isText() bool { return true }
// newPlainText creates a new PlainText. It returns a *PlainText. // newPlainText creates a new PlainText. It returns a *PlainText.
func newPlainText(textType, content string) *PlainText { func newPlainText(textType, content string) *PlainText {
return &PlainText{ return &PlainText{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Type: textType, Type: textType,
Text: content, Text: content,
} }

View File

@ -25,12 +25,13 @@ type Source struct {
// NewSource creates a new Source. It returns a *Source. // NewSource creates a new Source. It returns a *Source.
func NewSource() *Source { func NewSource() *Source {
return &Source{CommonAttributes: newCommonAttributes()} return &Source{CommonAttributes: NewCommonAttributes()}
} }
// AddAuthor adds the Person as an author to the Source. // AddAuthor adds the Person as an author to the Source. It returns its index as
func (s *Source) AddAuthor(p *Person) { // an int.
addToSlice(&s.Authors, p) func (s *Source) AddAuthor(p *Person) int {
return addToSlice(&s.Authors, p)
} }
// DeleteAuthor deletes the Person at index from the Source. It return an error. // DeleteAuthor deletes the Person at index from the Source. It return an error.
@ -41,9 +42,9 @@ func (s *Source) DeleteAuthor(index int) error {
return nil return nil
} }
// AddCategory adds the Category to the Source. // AddCategory adds the Category to the Source. It returns its index as an int.
func (s *Source) AddCategory(c *Category) { func (s *Source) AddCategory(c *Category) int {
addToSlice(&s.Categories, c) return addToSlice(&s.Categories, c)
} }
// DeleteCategory deletes the Category at index from the Source. It return an // DeleteCategory deletes the Category at index from the Source. It return an
@ -55,9 +56,10 @@ func (s *Source) DeleteCategory(index int) error {
return nil return nil
} }
// AddContributor adds the Person as a contributor to the Source. // AddContributor adds the Person as a contributor to the Source. It returns its
func (s *Source) AddContributor(c *Person) { // index as an int.
addToSlice(&s.Contributors, c) func (s *Source) AddContributor(c *Person) int {
return addToSlice(&s.Contributors, c)
} }
// DeleteContributor deletes the Person at index from the Source. It return an // DeleteContributor deletes the Person at index from the Source. It return an
@ -69,9 +71,9 @@ func (s *Source) DeleteContributor(index int) error {
return nil return nil
} }
// AddLink adds the Link to the Source. // AddLink adds the Link to the Source. It returns its index as an int.
func (s *Source) AddLink(l *Link) { func (s *Source) AddLink(l *Link) int {
addToSlice(&s.Links, l) return addToSlice(&s.Links, l)
} }
// DeleteLink deletes the Link at index from the Source. It return an error. // DeleteLink deletes the Link at index from the Source. It return an error.
@ -82,9 +84,10 @@ func (s *Source) DeleteLink(index int) error {
return nil return nil
} }
// AddExtension adds the ExtensionElement to the Source. // AddExtension adds the ExtensionElement to the Source. It returns its index as
func (s *Source) AddExtension(e *ExtensionElement) { // an int.
addToSlice(&s.Extensions, e) func (s *Source) AddExtension(e *ExtensionElement) int {
return addToSlice(&s.Extensions, e)
} }
// DeleteExtension deletes the Extension at index from the Source. It return an // DeleteExtension deletes the Extension at index from the Source. It return an

View File

@ -16,7 +16,7 @@ func (x *XHTMLText) isText() bool { return true }
// newPlainText creates a new PlainText. It returns a *PlainText. // newPlainText creates a new PlainText. It returns a *PlainText.
func newXHTMLText(textType, content string) *XHTMLText { func newXHTMLText(textType, content string) *XHTMLText {
return &XHTMLText{ return &XHTMLText{
CommonAttributes: newCommonAttributes(), CommonAttributes: NewCommonAttributes(),
Type: textType, Type: textType,
XHTMLDiv: NewXHTMLDiv(content), XHTMLDiv: NewXHTMLDiv(content),
} }