11 Commits

24 changed files with 367 additions and 220 deletions

119
README.md
View File

@ -14,6 +14,8 @@ go get git.streifling.com/jason/atom@latest
## Usage
### Basic Feed
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.
@ -48,7 +50,7 @@ func main() {
}
feed.AddEntry(entry)
feedString, err := feed.ToXML("utf-8")
feedString, err := feed.ToXML("UTF-8")
if err != nil {
log.Fatalln(err)
}
@ -68,6 +70,7 @@ import (
"time"
"git.streifling.com/jason/atom"
"github.com/google/uuid"
)
func main() {
@ -78,7 +81,7 @@ func main() {
Type: "text",
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)},
Authors: []*atom.Person{
{
@ -92,7 +95,7 @@ func main() {
Type: "text",
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)},
Content: &atom.InlineTextContent{
Type: "text",
@ -102,7 +105,7 @@ func main() {
},
}
feedString, err := feed.ToXML("utf-8")
feedString, err := feed.ToXML("UTF-8")
if err != nil {
log.Fatalln(err)
}
@ -113,7 +116,7 @@ func main() {
The output of both ways of using it is an RFC4287 compliant Atom feed.
```xml
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<author>
<name>John Doe</name>
@ -130,3 +133,109 @@ The output of both ways of using it is an RFC4287 compliant Atom feed.
</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>
```

38
atom.go
View File

@ -16,18 +16,19 @@ type Countable interface {
*xml.Attr | *Person | *Category | *Link | *ExtensionElement | *Entry
}
// addToSlice adds a Countable to to a *[]Countable. It returns an int.
// addToSlice adds a Countable countable to to a *[]Countable slice. It returns
// the index as an int.
func addToSlice[C Countable](slice *[]C, countable C) int {
if *slice == nil {
*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.
// It return an error.
// deleteFromSlice deletes the Countable at index from the *[]Countable slice.
// It returns an error.
func deleteFromSlice[C Countable](slice *[]C, index int) error {
length := len(*slice)
if index > length {
@ -45,7 +46,7 @@ func isValidIRI(iri string) bool {
return regexp.MustCompile(pattern).MatchString(iri)
}
// isCorrectlyEscaped checks whether a string is correctly escaped as per
// isCorrectlyEscaped checks whether the text is correctly escaped as per
// RFC4287. It returns a bool.
func isCorrectlyEscaped(text string) bool {
relevantEntities := []string{"&amp;", "&lt;", "&gt;", "&quot;", "&apos;"}
@ -59,8 +60,8 @@ func isCorrectlyEscaped(text string) bool {
return true
}
// isCompositeMediaType checks whether a string is a composite media type. It
// returns a bool.
// isCompositeMediaType checks whether the string m is a composite media type.
// It returns a bool.
func isCompositeMediaType(m string) bool {
mediaType, _, err := mime.ParseMediaType(m)
if err != nil {
@ -70,7 +71,7 @@ func isCompositeMediaType(m string) bool {
return strings.HasPrefix(mediaType, "multipart/") || strings.HasPrefix(mediaType, "message/")
}
// isXMLMediaType checks whether a string is an xml media type. It returns a
// isXMLMediaType checks whether the string m is an xml media type. It returns a
// bool.
func isXMLMediaType(m string) bool {
mediaType, _, err := mime.ParseMediaType(m)
@ -81,8 +82,8 @@ func isXMLMediaType(m string) bool {
return strings.HasSuffix(mediaType, "/xml") || strings.HasSuffix(mediaType, "+xml")
}
// isValidMediaType checks whether a string is a valid media type. It returns a
// bool.
// isValidMediaType checks whether the string m is a valid media type. It
// returns a bool.
func isValidMediaType(m string) bool {
mediaType, _, err := mime.ParseMediaType(m)
if err != nil {
@ -90,23 +91,20 @@ func isValidMediaType(m string) bool {
}
typeParts := strings.Split(mediaType, "/")
if len(typeParts) != 2 || typeParts[0] == "" || typeParts[1] == "" {
return false
}
return true
return len(typeParts) == 2 && typeParts[0] != "" && typeParts[1] != ""
}
// isValidLanguageTag checks whether a LanguageTag is valid. It returns a bool.
// isValidLanguageTag checks whether the string languageTag is valid. It returns
// a bool.
func isValidLanguageTag(languageTag string) bool {
_, err := language.Parse(languageTag)
return err == nil
}
// isValidAttribute checks whether an Attribute is valid. It returns a bool.
// isValidAttribute checks whether the string attribute is valid. It returns a
// bool.
func isValidAttribute(attribute string) bool {
regex := regexp.MustCompile(`^[a-zA-Z0-9_]+="[^"]*"$`)
return regex.MatchString(attribute)
return regexp.MustCompile(`^[a-zA-Z0-9_]+="[^"]*"$`).MatchString(attribute)
}
// NewURN generates an new valid IRI based on a UUID. It returns an IRI.
@ -114,7 +112,7 @@ func NewURN() string {
return fmt.Sprint("urn:uuid:", uuid.New())
}
// Unescape unescapes a string. It returns an IRI.
// Unescape unescapes the string s. It returns an IRI.
func Unescape(s string) string {
return html.UnescapeString(s)
}

View File

@ -10,22 +10,18 @@ type Category struct {
*CommonAttributes
Term string `xml:"term,attr"`
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 takes in a string term and returns a
// *Category.
func NewCategory(term string) *Category {
return &Category{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
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
// error.
func (c *Category) Check() error {

View File

@ -13,17 +13,18 @@ type CommonAttributes struct {
// NewCommonAttributes creates a new set of CommonAttributes. It returns a
// *CommonAttributes.
func newCommonAttributes() *CommonAttributes {
func NewCommonAttributes() *CommonAttributes {
return new(CommonAttributes)
}
// AddAttribute adds the attribute to the CommonAttributes. It returns an int.
// AddAttribute adds an attribute to the CommonAttributes. It takes in the
// strings name and value and returns the index as an int.
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
// return an error.
// returns an error.
func (c *CommonAttributes) DeleteAttribute(index int) error {
if err := deleteFromSlice(&c.UndefinedAttributes, index); err != nil {
return fmt.Errorf("error deleting undefined attribute %v from common attributes %v: %v", index, c, err)

View File

@ -14,7 +14,10 @@ type Content interface {
Check() error
}
// NewContent creates a new Content. It returns a Content and an error.
// NewContent creates a new Content. It takes in an int contentType, a string
// mediaType and an any content and returns a Content.
//
// If contentType is invalid, it returns nil.
func NewContent(contentType int, mediaType string, content any) Content {
switch contentType {
case 0:

View File

@ -10,16 +10,16 @@ type Date struct {
DateTime string `xml:",chardata"`
}
// DateTime formats a time.Time to string formated as defined by RFC3339. It
// DateTime formats the time.Time t to a string as defined by RFC3339. It
// returns a string.
func DateTime(t time.Time) string {
return t.Format(time.RFC3339)
}
// NewDate creates a new Date. It returns a *Date.
// NewDate creates a new Date. It takes in a time.Time t and returns a *Date.
func NewDate(t time.Time) *Date {
return &Date{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
DateTime: DateTime(t),
}
}

View File

@ -30,14 +30,15 @@ type Entry struct {
}
// checkAuthors checks the entry's authors for incompatibilities with RFC4287.
// It returns an errors.
// It takes in a bool authorIsInFeed and returns an errors.
//
// atom:entry elements MUST contain one or more atom:author elements, unless
// the atom:entry contains an atom:source element that contains an atom:author
// element or, in an Atom Feed Document, the atom:feed element contains an
// atom:author element itself.
func (e *Entry) checkAuthors(authorInFeed bool) error {
func (e *Entry) checkAuthors(authorIsInFeed bool) error {
if e.Authors == nil {
if !authorInFeed {
if !authorIsInFeed {
if e.Source == nil {
return fmt.Errorf("no authors set in entry %v", e.ID.URI)
}
@ -56,97 +57,109 @@ func (e *Entry) checkAuthors(authorInFeed bool) error {
return nil
}
// NewEntry creates a new Entry. It returns a *Entry.
// update sets the Updated time to time.Now.
func (e *Entry) update() {
if e.Updated == nil {
e.Updated = NewDate(time.Now())
} else {
e.Updated.DateTime = DateTime(time.Now())
}
}
// NewEntry creates a new Entry. It takes in a string title and returns a
// *Entry.
func NewEntry(title string) *Entry {
return &Entry{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
ID: NewID(NewURN()),
Title: NewText("text", title),
Updated: NewDate(time.Now()),
}
}
// AddAuthor adds the Person as an author to the Entry. It returns an int.
func (e *Entry) AddAuthor(p *Person) int {
e.Updated = NewDate(time.Now())
return addToSlice(&e.Authors, p)
// AddAuthor adds the Person a as an author to the Entry. It returns the index
// as an int.
func (e *Entry) AddAuthor(a *Person) int {
e.update()
return addToSlice(&e.Authors, a)
}
// DeleteAuthor deletes the Person at index from the Entry. It return an error.
// DeleteAuthor deletes the Person at index from the Entry. It returns an error.
func (e *Entry) DeleteAuthor(index int) error {
if err := deleteFromSlice(&e.Authors, index); err != nil {
return fmt.Errorf("error deleting author %v from entry %v: %v", index, e.ID.URI, err)
}
e.Updated = NewDate(time.Now())
e.update()
return nil
}
// AddCategory adds the Category to the Entry. It returns an int.
// AddCategory adds the Category c to the Entry. It returns the index as an int.
func (e *Entry) AddCategory(c *Category) int {
e.Updated = NewDate(time.Now())
e.update()
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 returns an
// error.
func (e *Entry) DeleteCategory(index int) error {
if err := deleteFromSlice(&e.Categories, index); err != nil {
return fmt.Errorf("error deleting category %v from entry %v: %v", index, e.ID.URI, err)
}
e.Updated = NewDate(time.Now())
e.update()
return nil
}
// AddContributor adds the Person as a contributor to the Entry. It returns an
// int.
// AddContributor adds the Person c as a contributor to the Entry. It returns
// the index as an int.
func (e *Entry) AddContributor(c *Person) int {
e.Updated = NewDate(time.Now())
e.update()
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 returns an
// error.
func (e *Entry) DeleteContributor(index int) error {
if err := deleteFromSlice(&e.Contributors, index); err != nil {
return fmt.Errorf("error deleting contributor %v from entry %v: %v", index, e.ID.URI, err)
}
e.Updated = NewDate(time.Now())
e.update()
return nil
}
// AddLink adds the Link to the Entry. It returns an int.
// AddLink adds the Link l to the Entry. It returns the index as an int.
func (e *Entry) AddLink(l *Link) int {
e.Updated = NewDate(time.Now())
e.update()
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 returns an error.
func (e *Entry) DeleteLink(index int) error {
if err := deleteFromSlice(&e.Links, index); err != nil {
return fmt.Errorf("error deleting link %v from entry %v: %v", index, e.ID.URI, err)
}
e.Updated = NewDate(time.Now())
e.update()
return nil
}
// AddExtension adds the ExtensionElement to the Entry. It returns an int.
// AddExtension adds the ExtensionElement x to the Entry. It returns the index
// as an int.
func (e *Entry) AddExtension(x *ExtensionElement) int {
e.Updated = NewDate(time.Now())
e.update()
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 returns an
// error.
func (e *Entry) DeleteExtension(index int) error {
if err := deleteFromSlice(&e.Extensions, index); err != nil {
return fmt.Errorf("error deleting extension %v from entry %v: %v", index, e.ID.URI, err)
}
e.Updated = NewDate(time.Now())
e.update()
return nil
}
@ -264,7 +277,8 @@ func (e *Entry) Check() error {
return nil
}
// ToXML converts the Feed to XML. It returns a string and an error.
// ToXML converts the Feed to XML. It takes in a string encoding and returns a
// string and an error.
func (e *Entry) ToXML(encoding string) (string, error) {
xml, err := xml.MarshalIndent(e, "", " ")
if err != nil {

View File

@ -10,8 +10,8 @@ type ExtensionElement struct {
XMLName xml.Name
}
// NewExtensionElement creates a new ExtensionElement. It returns a
// *ExtensionElement.
// NewExtensionElement creates a new ExtensionElement. It takes in a string name
// and any value and returns a *ExtensionElement.
func NewExtensionElement(name string, value any) *ExtensionElement {
return &ExtensionElement{XMLName: xml.Name{Local: name}, Value: value}
}

78
feed.go
View File

@ -25,118 +25,131 @@ type Feed struct {
Entries []*Entry `xml:",omitempty"`
}
// NewFeed creates a new Feed. It returns a *Feed.
// update sets the Updated time to time.Now.
func (f *Feed) update() {
if f.Updated == nil {
f.Updated = NewDate(time.Now())
} else {
f.Updated.DateTime = DateTime(time.Now())
}
}
// NewFeed creates a new Feed. It takes in a string title and returns a *Feed.
func NewFeed(title string) *Feed {
return &Feed{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
ID: NewID(NewURN()),
Title: NewText("text", title),
Updated: NewDate(time.Now()),
}
}
// AddAuthor adds the Person as an author to the Feed. It returns an int.
func (f *Feed) AddAuthor(p *Person) int {
f.Updated = NewDate(time.Now())
return addToSlice(&f.Authors, p)
// AddAuthor adds the Person a as an author to the Feed. It returns the index as
// an int.
func (f *Feed) AddAuthor(a *Person) int {
f.update()
return addToSlice(&f.Authors, a)
}
// DeleteAuthor deletes the Person at index from the Feed. It return an error.
// DeleteAuthor deletes the Person at index from the Feed. It returns an error.
func (f *Feed) DeleteAuthor(index int) error {
if err := deleteFromSlice(&f.Authors, index); err != nil {
return fmt.Errorf("error deleting author %v from entry %v: %v", index, f.ID.URI, err)
}
f.Updated = NewDate(time.Now())
f.update()
return nil
}
// AddCategory adds the Category to the Feed. It returns an int.
// AddCategory adds the Category c to the Feed. It returns the index as an int.
func (f *Feed) AddCategory(c *Category) int {
f.Updated = NewDate(time.Now())
f.update()
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 returns an
// error.
func (f *Feed) DeleteCategory(index int) error {
if err := deleteFromSlice(&f.Categories, index); err != nil {
return fmt.Errorf("error deleting category %v from entry %v: %v", index, f.ID.URI, err)
}
f.Updated = NewDate(time.Now())
f.update()
return nil
}
// AddContributor adds the Person as a contributor to the Feed. It returns an
// int.
// AddContributor adds the Person c as a contributor to the Feed. It returns the
// index as an int.
func (f *Feed) AddContributor(c *Person) int {
f.Updated = NewDate(time.Now())
f.update()
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 returns an
// error.
func (f *Feed) DeleteContributor(index int) error {
if err := deleteFromSlice(&f.Contributors, index); err != nil {
return fmt.Errorf("error deleting contributor %v from entry %v: %v", index, f.ID.URI, err)
}
f.Updated = NewDate(time.Now())
f.update()
return nil
}
// AddLink adds the Link to the Feed. There should be one Link with Rel "self".
// It returns an int.
// AddLink adds the Link l to the Feed. It returns the index as an int.
//
// There should be one Link with Rel "self".
func (f *Feed) AddLink(l *Link) int {
f.Updated = NewDate(time.Now())
f.update()
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 returns an error.
func (f *Feed) DeleteLink(index int) error {
if err := deleteFromSlice(&f.Links, index); err != nil {
return fmt.Errorf("error deleting link %v from entry %v: %v", index, f.ID.URI, err)
}
f.Updated = NewDate(time.Now())
f.update()
return nil
}
// AddExtension adds the Extension to the Feed. It returns an int.
// AddExtension adds the Extension e to the Feed. It returns the index as an
// int.
func (f *Feed) AddExtension(e *ExtensionElement) int {
f.Updated = NewDate(time.Now())
f.update()
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 returns an
// error.
func (f *Feed) DeleteExtension(index int) error {
if err := deleteFromSlice(&f.Extensions, index); err != nil {
return fmt.Errorf("error deleting extension %v from entry %v: %v", index, f.ID.URI, err)
}
f.Updated = NewDate(time.Now())
f.update()
return nil
}
// AddEntry adds the Entry to the Feed. It returns an int.
// AddEntry adds the Entry e to the Feed. It returns the index as an int.
func (f *Feed) AddEntry(e *Entry) int {
f.Updated = NewDate(time.Now())
f.update()
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 returns an error.
func (f *Feed) DeleteEntry(index int) error {
if err := deleteFromSlice(&f.Entries, index); err != nil {
return fmt.Errorf("error deleting entry %v from entry %v: %v", index, f.ID.URI, err)
}
f.Updated = NewDate(time.Now())
f.update()
return nil
}
// DeleteEntryByURI deletes the Entry from the Feed. It return an error.
// DeleteEntryByURI deletes the Entry from the Feed. It takes in a string uri
// and returns an error.
func (f *Feed) DeleteEntryByURI(uri string) error {
if !isValidIRI(uri) {
return fmt.Errorf("error deleting entry from feed %v: uri %v invalid", f.ID.URI, uri)
@ -154,7 +167,8 @@ func (f *Feed) DeleteEntryByURI(uri string) error {
}
f.Entries = append(f.Entries[:index], f.Entries[index+1:]...)
f.Updated = NewDate(time.Now())
f.update()
return nil
}

View File

@ -14,10 +14,11 @@ type Generator struct {
Text string `xml:",chardata"`
}
// NewGenerator creates a new Generator. It returns a *Generator.
// NewGenerator creates a new Generator. It takes in a string text and returns a
// *Generator.
func NewGenerator(text string) *Generator {
return &Generator{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
Text: html.UnescapeString(text),
}
}

View File

@ -12,10 +12,10 @@ type Icon struct {
URI string `xml:",chardata"` // IRI
}
// NewIcon creates a new Icon. It returns a *Icon.
// NewIcon creates a new Icon. It takes in a string uri and returns a *Icon.
func NewIcon(uri string) *Icon {
return &Icon{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
URI: uri,
}
}

4
id.go
View File

@ -12,10 +12,10 @@ type ID struct {
URI string `xml:",chardata"` // IRI
}
// NewID creates a new ID. It returns a *ID.
// NewID creates a new ID. It takes in a string uri and returns a *ID.
func NewID(uri string) *ID {
return &ID{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
URI: uri,
}
}

View File

@ -13,13 +13,13 @@ type InlineOtherContent struct {
Type string `xml:"type,attr,omitempty"` // MediaType
}
// newInlineOtherContent creates a new InlineOtherContent. It returns a
// *InlineOtherContent and an error.
// newInlineOtherContent creates a new InlineOtherContent. It takes in the string
// mediaType and any content and returns a *InlineOtherContent and an error.
func newInlineOtherContent(mediaType string, content any) *InlineOtherContent {
mediaType, _, _ = mime.ParseMediaType(mediaType)
return &InlineOtherContent{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
Type: mediaType,
AnyElement: content,
}

View File

@ -12,11 +12,11 @@ type InlineTextContent struct {
Text string `xml:",chardata"`
}
// newInlineTextContent creates a new InlineTextContent. It returns a
// *InlineTextContent.
// newInlineTextContent creates a new InlineTextContent. It takes in the strings
// mediaType and text and returns a *InlineTextContent.
func newInlineTextContent(mediaType, text string) *InlineTextContent {
return &InlineTextContent{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
Type: mediaType,
Text: text,
}

View File

@ -12,11 +12,11 @@ type InlineXHTMLContent struct {
Type string `xml:"type,attr"`
}
// newInlineXHTMLContent creates a new InlineXHTMLContent. It returns a
// *InlineXHTMLContent.
// newInlineXHTMLContent creates a new InlineXHTMLContent. It takes in the
// string mediaType and the XHTMLDiv div and returns a *InlineXHTMLContent.
func newInlineXHTMLContent(mediaType string, div *XHTMLDiv) *InlineXHTMLContent {
return &InlineXHTMLContent{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
Type: mediaType,
XHTMLDiv: div,
}

View File

@ -17,10 +17,10 @@ type Link struct {
Length uint `xml:"length,attr,omitempty"`
}
// NewLink creates a new Link. It returns a *Link.
// NewLink creates a new Link. It takes in the string href and returns a *Link.
func NewLink(href string) *Link {
return &Link{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
Href: href,
}
}

View File

@ -11,10 +11,10 @@ type Logo struct {
URI string `xml:",chardata"` // IRI
}
// NewLogo creates a new Logo. It returns a *Logo.
// NewLogo creates a new Logo. It takes in a string uri and returns a *Logo.
func NewLogo(uri string) *Logo {
return &Logo{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
URI: uri,
}
}

View File

@ -13,13 +13,13 @@ type OutOfLineContent struct {
SRC string `xml:"src,attr"` // IRI
}
// newOutOfLineContent creates a new OutOfLineContent. It returns a
// *OutOfLineContent.
// newOutOfLineContent creates a new OutOfLineContent. It takes in the strings
// mediaType and src and returns a *OutOfLineContent.
func newOutOfLineContent(mediaType, src string) *OutOfLineContent {
mediaType, _, _ = mime.ParseMediaType(mediaType)
return &OutOfLineContent{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
Type: mediaType,
SRC: src,
}

View File

@ -13,20 +13,22 @@ type Person struct {
Extensions []*ExtensionElement `xml:",any,omitempty"`
}
// NewPerson creates a new Person. It returns a *Person.
// NewPerson creates a new Person. It takes in a string name and returns a
// *Person.
func NewPerson(name string) *Person {
return &Person{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
Name: name,
}
}
// AddExtension adds the Extension to the Person. It returns an int.
// AddExtension adds the Extension e to the Person. It returns the index as an
// int.
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 returns an
// error.
func (p *Person) DeleteExtension(index int) error {
if err := deleteFromSlice(&p.Extensions, index); err != nil {

View File

@ -13,10 +13,11 @@ type PlainText struct {
// isText checks whether the PlainText is a Text. It returns a bool.
func (p *PlainText) isText() bool { return true }
// newPlainText creates a new PlainText. It returns a *PlainText.
// newPlainText creates a new PlainText. It takes in the strings textType and
// content and returns a *PlainText.
func newPlainText(textType, content string) *PlainText {
return &PlainText{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
Type: textType,
Text: content,
}

View File

@ -25,15 +25,17 @@ type Source struct {
// NewSource creates a new Source. It returns a *Source.
func NewSource() *Source {
return &Source{CommonAttributes: newCommonAttributes()}
return &Source{CommonAttributes: NewCommonAttributes()}
}
// AddAuthor adds the Person as an author to the Source. It returns an int.
func (s *Source) AddAuthor(p *Person) int {
return addToSlice(&s.Authors, p)
// AddAuthor adds the Person a as an author to the Source. It returns the index
// as an int.
func (s *Source) AddAuthor(a *Person) int {
return addToSlice(&s.Authors, a)
}
// DeleteAuthor deletes the Person at index from the Source. It return an error.
// DeleteAuthor deletes the Person at index from the Source. It returns an
// error.
func (s *Source) DeleteAuthor(index int) error {
if err := deleteFromSlice(&s.Authors, index); err != nil {
return fmt.Errorf("error deleting author %v from source %v: %v", index, s, err)
@ -41,12 +43,12 @@ func (s *Source) DeleteAuthor(index int) error {
return nil
}
// AddCategory adds the Category to the Source. It returns an int.
// AddCategory adds the Category c to the Source. It returns the index as an int.
func (s *Source) AddCategory(c *Category) int {
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 returns an
// error.
func (s *Source) DeleteCategory(index int) error {
if err := deleteFromSlice(&s.Categories, index); err != nil {
@ -55,13 +57,13 @@ func (s *Source) DeleteCategory(index int) error {
return nil
}
// AddContributor adds the Person as a contributor to the Source. It returns an
// int.
// AddContributor adds the Person c as a contributor to the Source. It returns
// the index as an int.
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 returns an
// error.
func (s *Source) DeleteContributor(index int) error {
if err := deleteFromSlice(&s.Contributors, index); err != nil {
@ -70,12 +72,12 @@ func (s *Source) DeleteContributor(index int) error {
return nil
}
// AddLink adds the Link to the Source. It returns an int.
// AddLink adds the Link l to the Source. It returns the index as an int.
func (s *Source) AddLink(l *Link) int {
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 returns an error.
func (s *Source) DeleteLink(index int) error {
if err := deleteFromSlice(&s.Links, index); err != nil {
return fmt.Errorf("error deleting link %v from source %v: %v", index, s, err)
@ -83,12 +85,13 @@ func (s *Source) DeleteLink(index int) error {
return nil
}
// AddExtension adds the ExtensionElement to the Source. It returns an int.
// AddExtension adds the ExtensionElement e to the Source. It returns the index
// as an int.
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 returns an
// error.
func (s *Source) DeleteExtension(index int) error {
if err := deleteFromSlice(&s.Extensions, index); err != nil {

View File

@ -7,7 +7,10 @@ type Text interface {
Check() error
}
// NewText creates a new Text. It returns a Text.
// NewText creates a new Text. It takes in the strings textType and content and
// returns a Text.
//
// If textType is invalid it returns nil.
func NewText(textType, content string) Text {
switch textType {
case "text", "":

View File

@ -11,7 +11,8 @@ type XHTMLDiv struct {
Content string `xml:",innerxml"`
}
// NewXHTMLDiv creates a new XHTMLDiv. It returns a *XHTMLDiv.
// NewXHTMLDiv creates a new XHTMLDiv. It takes in a string content and returns
// a *XHTMLDiv.
func NewXHTMLDiv(content string) *XHTMLDiv {
return &XHTMLDiv{
XMLNS: "http://www.w3.org/1999/xhtml",

View File

@ -13,10 +13,11 @@ type XHTMLText struct {
// isText checks whether the XHTMLText is a Text. It returns a bool.
func (x *XHTMLText) isText() bool { return true }
// newPlainText creates a new PlainText. It returns a *PlainText.
// newPlainText creates a new PlainText. It takes in the strings textType and
// content and returns a *PlainText.
func newXHTMLText(textType, content string) *XHTMLText {
return &XHTMLText{
CommonAttributes: newCommonAttributes(),
CommonAttributes: NewCommonAttributes(),
Type: textType,
XHTMLDiv: NewXHTMLDiv(content),
}