96 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package atom
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| type Link struct {
 | |
| 	*CommonAttributes
 | |
| 	Title    string      `xml:"title,attr,omitempty"`
 | |
| 	Content  Content     `xml:"content"` // undefinedContent in RFC4287
 | |
| 	Href     IRI         `xml:"href,attr"`
 | |
| 	Rel      string      `xml:"rel,attr,omitempty"`
 | |
| 	Type     MediaType   `xml:"type,attr,omitempty"`
 | |
| 	HrefLang LanguageTag `xml:"hreflang,attr,omitempty"`
 | |
| 	Length   uint        `xml:"length,attr,omitempty"`
 | |
| }
 | |
| 
 | |
| // NewLink creates a new Link. It returns a *Link and an error.
 | |
| func NewLink(href string) (*Link, error) {
 | |
| 	content, err := NewContent(InlineText, "", "")
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("error creating content element: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	return &Link{Href: IRI(href), Content: content}, nil
 | |
| }
 | |
| 
 | |
| // Check checks the Link for incompatibilities with RFC4287. It returns an
 | |
| // error.
 | |
| func (l *Link) Check() error {
 | |
| 	if l.Href == "" {
 | |
| 		return errors.New("href attribute of link empty")
 | |
| 	} else {
 | |
| 		if !isValidIRI(l.Href) {
 | |
| 			return fmt.Errorf("href attribute %v of link not correctly formatted", l.Href)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if strings.Contains(l.Rel, ":") && !isValidIRI(IRI(l.Rel)) {
 | |
| 		return fmt.Errorf("rel attribute %v of link %v not correctly formatted", l.Rel, l.Href)
 | |
| 	}
 | |
| 
 | |
| 	if !isValidMediaType(string(l.Type)) {
 | |
| 		return fmt.Errorf("type attribute %v of link %v invalid media type", l.Type, l.Href)
 | |
| 	}
 | |
| 
 | |
| 	if !isValidLanguageTag(l.HrefLang) {
 | |
| 		return fmt.Errorf("hreflang attribute %v of link %v invalid language tag", l.Type, l.HrefLang)
 | |
| 	}
 | |
| 
 | |
| 	if l.Content == nil {
 | |
| 		return fmt.Errorf("no content element of link %v", l.Href)
 | |
| 	} else {
 | |
| 		if err := l.Content.Check(); err != nil {
 | |
| 			return fmt.Errorf("content element of link %v: %v", l.Href, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // hasAlternateDuplicateLinks checks whether multiple Links with Rel
 | |
| // "alternate" also have Type and HrefLang in common. It returns a bool.
 | |
| // atom:feed/entry elements MUST NOT contain more than one atom:link element
 | |
| // with a rel attribute value of "alternate" that has the same combination of
 | |
| // type and hreflang attribute values.
 | |
| func hasAlternateDuplicateLinks(l []*Link) bool {
 | |
| 	linkMap := make(map[string]bool)
 | |
| 
 | |
| 	for _, link := range l {
 | |
| 		if link.Rel == "alternate" {
 | |
| 			key := fmt.Sprint(link.Type, "|", link.HrefLang)
 | |
| 			if linkMap[key] {
 | |
| 				return true
 | |
| 			}
 | |
| 			linkMap[key] = true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // alternateRelExists checks whether multiple Links with Rel "alternate" exist.
 | |
| // It returns a bool.
 | |
| func alternateRelExists(l []*Link) bool {
 | |
| 	for _, link := range l {
 | |
| 		if link.Rel == "alternate" {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 |