Compare commits
	
		
			14 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f3019ff7e8 | |||
| d6310ee8ee | |||
| a65920aa70 | |||
| 9ab48787d4 | |||
| be79a13d48 | |||
| 089c573aed | |||
| d8d0526a05 | |||
| 8fc6a10b0d | |||
| 0b70a8ee10 | |||
| da5d955b2d | |||
| ee72e91593 | |||
| ddf5b26a1e | |||
| cf131f0bcf | |||
| ae24db0c08 | 
							
								
								
									
										119
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								README.md
									
									
									
									
									
								
							| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								atom.go
									
									
									
									
									
								
							| @@ -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{"&", "<", ">", """, "'"} | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
							
								
								
									
										12
									
								
								category.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								category.go
									
									
									
									
									
								
							| @@ -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 { | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
							
								
								
									
										20
									
								
								content.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								content.go
									
									
									
									
									
								
							| @@ -14,17 +14,29 @@ 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: | ||||
| 		return newInlineTextContent(mediaType, content.(string)) | ||||
| 		if stringContent, ok := content.(string); ok { | ||||
| 			return newInlineTextContent(mediaType, stringContent) | ||||
| 		} | ||||
| 		return nil | ||||
| 	case 1: | ||||
| 		return newInlineXHTMLContent(mediaType, content.(*XHTMLDiv)) | ||||
| 		if xhtmlDivContent, ok := content.(*XHTMLDiv); ok { | ||||
| 			return newInlineXHTMLContent(mediaType, xhtmlDivContent) | ||||
| 		} | ||||
| 		return nil | ||||
| 	case 2: | ||||
| 		return newInlineOtherContent(mediaType, content) | ||||
| 	case 3: | ||||
| 		return newOutOfLineContent(mediaType, content.(string)) | ||||
| 		if stringContent, ok := content.(string); ok { | ||||
| 			return newOutOfLineContent(mediaType, stringContent) | ||||
| 		} | ||||
| 		return nil | ||||
| 	default: | ||||
| 		return nil | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										6
									
								
								date.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								date.go
									
									
									
									
									
								
							| @@ -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), | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										72
									
								
								entry.go
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								entry.go
									
									
									
									
									
								
							| @@ -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 { | ||||
|   | ||||
| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								feed.go
									
									
									
									
									
								
							| @@ -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 | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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), | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | ||||
| module git.streifling.com/jason/atom | ||||
|  | ||||
| go 1.23.2 | ||||
| go 1.24.0 | ||||
|  | ||||
| require ( | ||||
| 	github.com/google/uuid v1.6.0 | ||||
| 	golang.org/x/text v0.19.0 | ||||
| 	golang.org/x/text v0.29.0 | ||||
| ) | ||||
|   | ||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | ||||
| github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= | ||||
| golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= | ||||
| golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= | ||||
| golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= | ||||
|   | ||||
							
								
								
									
										4
									
								
								icon.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								icon.go
									
									
									
									
									
								
							| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								id.go
									
									
									
									
									
								
							| @@ -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, | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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, | ||||
| 	} | ||||
|   | ||||
| @@ -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, | ||||
| 	} | ||||
|   | ||||
| @@ -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, | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										4
									
								
								link.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								link.go
									
									
									
									
									
								
							| @@ -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, | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								logo.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								logo.go
									
									
									
									
									
								
							| @@ -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, | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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, | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										10
									
								
								person.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								person.go
									
									
									
									
									
								
							| @@ -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 { | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| package atom | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
| import "fmt" | ||||
|  | ||||
| type PlainText struct { | ||||
| 	*CommonAttributes | ||||
| @@ -13,10 +11,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, | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										31
									
								
								source.go
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								source.go
									
									
									
									
									
								
							| @@ -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 { | ||||
|   | ||||
							
								
								
									
										5
									
								
								text.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								text.go
									
									
									
									
									
								
							| @@ -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", "": | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| package atom | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
| import "fmt" | ||||
|  | ||||
| type XHTMLText struct { | ||||
| 	*CommonAttributes | ||||
| @@ -13,10 +11,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), | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user