3 Commits

20 changed files with 92 additions and 72 deletions

View File

@ -15,8 +15,8 @@ go get git.streifling.com/jason/atom@latest
## Usage
This library provides convenient functions to safely create and extend elements
and attributes of an Atom feed. This is because it can be hard to know all
pitfalls of RFC4287. The intended way of using atom is with these functions.
and attributes of Atom feeds. It also provides checks for all constructs'
adherence to RFC4287.
```go
package main
@ -29,30 +29,28 @@ import (
)
func main() {
feed, err := atom.NewFeed("Example Feed")
if err != nil {
feed := atom.NewFeed("Example Feed")
feed.Title = atom.NewText("text", "Example Feed")
feed.ID = atom.NewID(atom.NewURN())
if err := feed.Check(); err != nil {
log.Fatalln(err)
}
author := atom.NewPerson("John Doe")
author.Email = "john.doe@example.com"
if err := author.Check(); err != nil {
log.Fatalln(err)
}
feed.AddAuthor(author)
entry, err := atom.NewEntry("First Entry")
if err != nil {
entry := atom.NewEntry("First Entry")
entry.ID = atom.NewID(atom.NewURN())
entry.Content = atom.NewContent(atom.InlineText, "text", "This is the content of the first entry.")
if err := entry.Check(); err != nil {
log.Fatalln(err)
}
content, err := atom.NewContent(atom.InlineText, "text", "This is the content of the first entry.")
if err != nil {
log.Fatalln(err)
}
entry.Content = content
feed.AddEntry(entry)
if err := feed.Check(); err != nil {
log.Fatalln(err)
}
feedString, err := feed.ToXML("utf-8")
if err != nil {
log.Fatalln(err)
@ -62,7 +60,7 @@ func main() {
```
It is also possible to use this library in a way similar to what other libraries
would provide. This is, of course, making it easier to make mistakes.
provide.
```go
package main
@ -115,7 +113,7 @@ func main() {
}
```
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 version="1.0" encoding="utf-8"?>

37
atom.go
View File

@ -11,10 +11,6 @@ import (
"golang.org/x/text/language"
)
func Unescape(s string) string {
return html.UnescapeString(s)
}
// isValidIRI checks whether an IRI is valid or not. It returns a bool.
// https://www.w3.org/2011/04/XMLSchema/TypeLibrary-IRI-RFC3987.xsd
func isValidIRI(iri string) bool {
@ -22,15 +18,6 @@ func isValidIRI(iri string) bool {
return regexp.MustCompile(pattern).MatchString(iri)
}
// NewIRI creates a new IRI. It returns a string and an error.
func NewIRI(iri string) (string, error) {
if !isValidIRI(iri) {
return "", fmt.Errorf("iri %v not correctly formatted", iri)
}
return iri, nil
}
// isCorrectlyEscaped checks whether a string is correctly escaped as per
// RFC4287. It returns a bool.
func isCorrectlyEscaped(text string) bool {
@ -83,31 +70,12 @@ func isValidMediaType(m string) bool {
return true
}
// NewMediaType creates a new MediaType. It returns a string and an error.
func NewMediaType(m string) (string, error) {
if !isValidMediaType(m) {
return "", fmt.Errorf("media type %v invalid", m)
}
mediaType, _, _ := mime.ParseMediaType(m)
return mediaType, nil
}
// isValidLanguageTag checks whether a LanguageTag is valid. It returns a bool.
func isValidLanguageTag(languageTag string) bool {
_, err := language.Parse(languageTag)
return err == nil
}
// NewLanguageTag creates a new LanguageTag. It returns a string and an error.
func NewLanguageTag(l string) (string, error) {
if !isValidLanguageTag(l) {
return "", fmt.Errorf("language tag %v invalid", l)
}
return l, nil
}
// isValidAttribute checks whether an Attribute is valid. It returns a bool.
func isValidAttribute(attribute string) bool {
regex := regexp.MustCompile(`^[a-zA-Z0-9_]+="[^"]*"$`)
@ -118,3 +86,8 @@ func isValidAttribute(attribute string) bool {
func NewURN() string {
return fmt.Sprint("urn:uuid:", uuid.New())
}
// Unescape unescapes a string. It returns an IRI.
func Unescape(s string) string {
return html.UnescapeString(s)
}

View File

@ -15,7 +15,10 @@ type Category struct {
// NewCategory creates a new Category. It returns a *Category.
func NewCategory(term string) *Category {
return &Category{Term: term}
return &Category{
CommonAttributes: newCommonAttributes(),
Term: term,
}
}
// SetLabel sets the Label attribute of the Category.

View File

@ -13,7 +13,7 @@ type CommonAttributes struct {
// NewCommonAttributes creates a new set of CommonAttributes. It returns a
// *CommonAttributes.
func NewCommonAttributes() *CommonAttributes {
func newCommonAttributes() *CommonAttributes {
return new(CommonAttributes)
}

View File

@ -18,7 +18,10 @@ func DateTime(t time.Time) string {
// NewDate creates a new Date. It returns a *Date.
func NewDate(t time.Time) *Date {
return &Date{DateTime: DateTime(t)}
return &Date{
CommonAttributes: newCommonAttributes(),
DateTime: DateTime(t),
}
}
// Check checks the Date for incompatibilities with RFC4287. It returns an

View File

@ -59,9 +59,10 @@ func (e *Entry) checkAuthors(authorInFeed bool) error {
// NewEntry creates a new Entry. It returns a *Entry.
func NewEntry(title string) *Entry {
return &Entry{
ID: NewID(NewURN()),
Title: NewText("text", title),
Updated: NewDate(time.Now()),
CommonAttributes: newCommonAttributes(),
ID: NewID(NewURN()),
Title: NewText("text", title),
Updated: NewDate(time.Now()),
}
}

View File

@ -28,9 +28,10 @@ type Feed struct {
// NewFeed creates a new Feed. It returns a *Feed.
func NewFeed(title string) *Feed {
return &Feed{
ID: NewID(NewURN()),
Title: NewText("text", title),
Updated: NewDate(time.Now()),
CommonAttributes: newCommonAttributes(),
ID: NewID(NewURN()),
Title: NewText("text", title),
Updated: NewDate(time.Now()),
}
}

View File

@ -16,7 +16,10 @@ type Generator struct {
// NewGenerator creates a new Generator. It returns a *Generator.
func NewGenerator(text string) *Generator {
return &Generator{Text: html.UnescapeString(text)}
return &Generator{
CommonAttributes: newCommonAttributes(),
Text: html.UnescapeString(text),
}
}
// Check checks the Generator for incompatibilities with RFC4287. It returns an

View File

@ -14,7 +14,10 @@ type Icon struct {
// NewIcon creates a new Icon. It returns a *Icon.
func NewIcon(uri string) *Icon {
return &Icon{URI: uri}
return &Icon{
CommonAttributes: newCommonAttributes(),
URI: uri,
}
}
// Check checks the Icon for incompatibilities with RFC4287. It returns an

5
id.go
View File

@ -14,7 +14,10 @@ type ID struct {
// NewID creates a new ID. It returns a *ID.
func NewID(uri string) *ID {
return &ID{URI: uri}
return &ID{
CommonAttributes: newCommonAttributes(),
URI: uri,
}
}
// Check checks the ID for incompatibilities with RFC4287. It returns an error.

View File

@ -17,7 +17,12 @@ type InlineOtherContent struct {
// *InlineOtherContent and an error.
func newInlineOtherContent(mediaType string, content any) *InlineOtherContent {
mediaType, _, _ = mime.ParseMediaType(mediaType)
return &InlineOtherContent{Type: mediaType, AnyElement: content}
return &InlineOtherContent{
CommonAttributes: newCommonAttributes(),
Type: mediaType,
AnyElement: content,
}
}
// isContent checks whether the InlineOtherContent is a Content. It returns a

View File

@ -15,7 +15,11 @@ type InlineTextContent struct {
// newInlineTextContent creates a new InlineTextContent. It returns a
// *InlineTextContent.
func newInlineTextContent(mediaType, text string) *InlineTextContent {
return &InlineTextContent{Type: mediaType, Text: text}
return &InlineTextContent{
CommonAttributes: newCommonAttributes(),
Type: mediaType,
Text: text,
}
}
// isContent checks whether the InlineTextContent is a Content. It returns a

View File

@ -15,7 +15,11 @@ type InlineXHTMLContent struct {
// newInlineXHTMLContent creates a new InlineXHTMLContent. It returns a
// *InlineXHTMLContent.
func newInlineXHTMLContent(mediaType string, div *XHTMLDiv) *InlineXHTMLContent {
return &InlineXHTMLContent{Type: mediaType, XHTMLDiv: div}
return &InlineXHTMLContent{
CommonAttributes: newCommonAttributes(),
Type: mediaType,
XHTMLDiv: div,
}
}
// isContent checks whether the InlineXHTMLContent is a Content. It returns a

View File

@ -19,7 +19,10 @@ type Link struct {
// NewLink creates a new Link. It returns a *Link.
func NewLink(href string) *Link {
return &Link{Href: href}
return &Link{
CommonAttributes: newCommonAttributes(),
Href: href,
}
}
// Check checks the Link for incompatibilities with RFC4287. It returns an

View File

@ -13,7 +13,10 @@ type Logo struct {
// NewLogo creates a new Logo. It returns a *Logo.
func NewLogo(uri string) *Logo {
return &Logo{URI: uri}
return &Logo{
CommonAttributes: newCommonAttributes(),
URI: uri,
}
}
// Check checks the Logo for incompatibilities with RFC4287. It returns an

View File

@ -17,7 +17,12 @@ type OutOfLineContent struct {
// *OutOfLineContent.
func newOutOfLineContent(mediaType, src string) *OutOfLineContent {
mediaType, _, _ = mime.ParseMediaType(mediaType)
return &OutOfLineContent{Type: mediaType, SRC: src}
return &OutOfLineContent{
CommonAttributes: newCommonAttributes(),
Type: mediaType,
SRC: src,
}
}
// isContent checks whether the OutOfLineContent is a Content. It returns a

View File

@ -15,7 +15,10 @@ type Person struct {
// NewPerson creates a new Person. It returns a *Person.
func NewPerson(name string) *Person {
return &Person{Name: name}
return &Person{
CommonAttributes: newCommonAttributes(),
Name: name,
}
}
// AddExtension adds the Extension to the Person.

View File

@ -15,7 +15,11 @@ func (p *PlainText) isText() bool { return true }
// newPlainText creates a new PlainText. It returns a *PlainText.
func newPlainText(textType, content string) *PlainText {
return &PlainText{Type: textType, Text: content}
return &PlainText{
CommonAttributes: newCommonAttributes(),
Type: textType,
Text: content,
}
}
// Check checks the PlainText for incompatibilities with RFC4287. It returns an

View File

@ -25,7 +25,7 @@ type Source struct {
// NewSource creates a new Source. It returns a *Source.
func NewSource() *Source {
return new(Source)
return &Source{CommonAttributes: newCommonAttributes()}
}
// Check checks the Source for incompatibilities with RFC4287. It returns an

View File

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