package classes
import "strings"
// The sitemap document is written by hand in the exact format PHP's
// DOMDocument::saveXML (libxml2) produced for the PHP plugin: the XML
// declaration and the stylesheet processing instruction each followed by a
// newline, everything else on one line, an empty urlset self-closed,
// xhtml:link elements self-closed without a space. The standard library's
// XML encoder escapes and closes elements differently, so the writer is a
// strings.Builder.
// The urlset opening tag's attributes, in the order PHP set them.
const urlsetAttrs = ` xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"` +
` xmlns:xhtml="http://www.w3.org/1999/xhtml"` +
` xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"` +
` xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"`
// textEscaper is libxml's escaping of text nodes: &, <, > and carriage
// return; quotes, tabs, newlines and UTF-8 stay literal.
var textEscaper = strings.NewReplacer("&", "&", "<", "<", ">", ">", "\r", "
")
// attrEscaper is libxml's escaping of attribute values: also the double
// quote, tab and newline; the single quote stays literal.
var attrEscaper = strings.NewReplacer(
"&", "&", "<", "<", ">", ">", `"`, """,
"\r", "
", "\t", " ", "\n", "
",
)
// EscapeText escapes s as libxml writes a text node.
func EscapeText(s string) string { return textEscaper.Replace(s) }
// EscapeAttr escapes s as libxml writes an attribute value.
func EscapeAttr(s string) string { return attrEscaper.Replace(s) }
// Alternate is one hreflang link of a sitemap URL.
type Alternate struct {
Hreflang string
Href string
}
// URLEntry is one url element: Loc, an optional Lastmod, Changefreq and
// Priority as they are written, the alternates (written only when there are
// more than one) and Extra, pre-escaped child XML that AddItem listeners
// appended, written before the closing tag.
type URLEntry struct {
Loc string
Lastmod string
Changefreq string
Priority string
Alternates []Alternate
Extra []string
}
// writeURL appends one url element.
func writeURL(b *strings.Builder, e URLEntry) {
b.WriteString("")
b.WriteString(EscapeText(e.Loc))
b.WriteString("")
if e.Lastmod != "" {
b.WriteString("")
b.WriteString(EscapeText(e.Lastmod))
b.WriteString("")
}
b.WriteString("")
b.WriteString(EscapeText(e.Changefreq))
b.WriteString("")
b.WriteString(EscapeText(e.Priority))
b.WriteString("")
if len(e.Alternates) > 1 {
for _, a := range e.Alternates {
b.WriteString(``)
}
}
for _, x := range e.Extra {
b.WriteString(x)
}
b.WriteString("")
}
// Serialize writes the sitemap document: the XML declaration, the
// stylesheet processing instruction pointing at stylesheet (written as it
// is, like libxml writes PI data) and the urlset with entries.
func Serialize(stylesheet string, entries []URLEntry) string {
var b strings.Builder
b.WriteString("\n")
b.WriteString(`\n\n")
return b.String()
}
b.WriteString(">")
for _, e := range entries {
writeURL(&b, e)
}
b.WriteString("\n")
return b.String()
}