Exemple #1
0
func ExtractTitle(data []byte, selector string) (title string, err error) {
	dec := xml.NewDecoder(bytes.NewReader(data))

	start, err := WalkNodePath(dec, selector)
	if err != nil {
		return "", err
	}

	if start.Name.Local == "title" {
		return html.XMLText(dec)
	}

	for {
		token, err := dec.Token()
		if err != nil {
			if err == io.EOF {
				return "", nil
			}
			return "", err
		}
		if _, done := token.(xml.EndElement); done {
			return "", nil
		}
		if start, isStart := token.(xml.StartElement); isStart {
			if start.Name.Local == "title" {
				return html.XMLText(dec)
			}
			dec.Skip()
		}
	}

	panic("unreachable")
}
func NewDefaultRules() *Rules {
	return &Rules{
		Rename: map[string]Renaming{
			// conversion
			"xref": {"a", ""},
			"link": {"a", ""},

			//lists
			"choices":         {"ul", ""},
			"choice":          {"li", ""},
			"steps-unordered": {"ul", ""},
			"steps":           {"ol", ""},
			"step":            {"li", ""}, // handled with a custom rule
			"substeps":        {"ol", ""},
			"substep":         {"li", ""}, // handled with a custom rule

			"b":     {"strong", ""},
			"i":     {"em", ""},
			"lines": {"pre", ""},

			"codeblock": {"pre", "codeblock"},
			"pre":       {"pre", "pre"},

			"codeph":      {"samp", "codeph"},
			"cmdname":     {"span", "cmdname"},
			"cmd":         {"span", "cmd"},
			"shortcut":    {"span", "shortcut"},
			"wintitle":    {"span", "wintitle"},
			"filepath":    {"span", "filepath"},
			"menucascade": {"span", "menucascade"},

			"option":   {"span", "option"},
			"synph":    {"span", ""},
			"delim":    {"span", ""},
			"sep":      {"span", ""},
			"parmname": {"span", ""},

			"userinput": {"kbd", "userinput"},

			"image": {"img", ""},

			// ui
			"uicontrol": {"b", ""},

			// divs
			"context":    {"div", ""},
			"result":     {"div", ""},
			"stepresult": {"div", ""},
			"stepxmp":    {"div", ""},
			"info":       {"div", ""},
			"note":       {"div", ""},
			"refsyn":     {"div", ""},
			"bodydiv":    {"div", ""},
			"fig":        {"div", ""},

			"prereq":  {"div", ""},
			"postreq": {"div", ""},

			"colspec": {"colgroup", ""},

			"row":   {"tr", ""},
			"entry": {"td", ""},

			// RAINTREE SPECIFIC
			"keystroke": {"b", "key"},
			"secright":  {"span", "secright"},

			// faq
			"faq":          {"dl", ""},
			"faq-item":     {"div", ""},
			"faq-question": {"dt", "dlterm"},
			"faq-answer":   {"dd", ""},

			//UI items
			"ui-item-list": {"dl", ""},
			"ui-item":      {"div", ""},
			//"ui-item-name":        {"dt", "dlterm"},
			"ui-item-description": {"dd", ""},

			// setup options
			"setup-options":            {"dl", ""},
			"setup-option":             {"div", ""},
			"setup-option-name":        {"dt", "dlterm"},
			"setup-option-description": {"dd", ""},

			"settingdesc": {"div", ""},
			"settingname": {"h2", ""},

			"section":    {"div", "section"},
			"example":    {"div", ""},
			"sectiondiv": {"div", ""},
			"title":      {"h2", "sectiontitle"},

			// ??
			"dlentry": {"div", ""},
			"dt":      {"dt", "dlterm"},

			"settings": {"div", "settings"},
			"setting":  {"div", "setting"},
		},
		Skip: map[string]bool{
			"br":            true,
			"draft-comment": true,

			// RAINTREE SPECIFIC
			"settinghead": true,
		},
		Unwrap: map[string]bool{
			"tgroup": true,
		},
		Custom: map[string]TokenProcessor{
			"a": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				var href, desc string
				var internal bool

				href = getAttr(&start, "href")
				if href != "" {
					href, _, desc, internal = context.ResolveLinkInfo(href)
					setAttr(&start, "href", href)
				}

				if desc != "" && getAttr(&start, "title") == "" {
					setAttr(&start, "title", desc)
				}

				setAttr(&start, "scope", "")
				if internal && href != "" {
					//setAttr(&start, "data-link", href)
				}

				if getAttr(&start, "format") != "" && href != "" {
					setAttr(&start, "format", "")
					ext := strings.ToLower(path.Ext(href))
					if ext == ".pdf" || ext == ".doc" || ext == ".xml" || ext == ".rtf" || ext == ".zip" || ext == ".exe" {
						setAttr(&start, "download", path.Base(href))
					} else {
						setAttr(&start, "target", "_blank")
					}
				}

				return context.EmitWithChildren(dec, start)
			},
			"img": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				href := getAttr(&start, "href")
				//setAttr(&start, "src", context.InlinedImageURL(href))
				setAttr(&start, "src", href)
				setAttr(&start, "href", "")

				placement := getAttr(&start, "placement")
				setAttr(&start, "placement", "")
				if placement == "break" {
					context.Encoder.WriteStart("p",
						xml.Attr{Name: xml.Name{Local: "class"}, Value: "image"})
				}

				err := context.EmitWithChildren(dec, start)

				if placement == "break" {
					context.Encoder.WriteEnd("p")
				}

				return err
			},
			"data": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				datatype := strings.ToLower(getAttr(&start, "datatype"))
				if datatype == "rttutorial" {
					dec.Skip()
					href := getAttr(&start, "href")
					tag := fmt.Sprintf(`<video controls src="%s">Browser does not support video playback.</video>`, html.NormalizeURL(href))
					context.Encoder.WriteRaw(tag)
					return nil
				}

				return context.EmitWithChildren(dec, start)
			},
			"imagemap": ConvertImageMap,

			// RAINTREE SPECIFIC
			"settingdefault": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				val, _ := html.XMLText(dec)
				if val != "" {
					return context.Encoder.WriteRaw("<p>Default value: " + val + "</p>")
				}
				return nil
			},
			"settinglevels": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				context.check(context.Encoder.WriteRaw("<p>Levels where it can be defined:</p>"))
				return context.EmitWithChildren(dec, start)
			},
			"settingsample": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				context.check(context.Encoder.WriteRaw("<p>Example:</p>"))
				return context.EmitWithChildren(dec, start)
			},

			"note": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				typ := getAttr(&start, "type")
				if typ == "other" {
					typ = getAttr(&start, "othertype")
				}
				if typ == "" {
					typ = "note"
				}
				setAttr(&start, "type", "")
				setAttr(&start, "othertype", "")
				setAttr(&start, "class", "note")
				mdiclass := "note-outline"
				switch typ {
				case "tip":
					mdiclass = "lightbulb-outline"
				case "caution":
					mdiclass = "alert"
				case "Extra":
					mdiclass = "key"
				case "Rev-Edition":
					mdiclass = "elevation-rise"
				}

				context.check(context.Encoder.WriteStart("div", start.Attr...))
				context.check(context.Encoder.WriteRaw(`<i class="mdi mdi-` + mdiclass + `" title="` + typ + `"></i> `))
				context.check(context.Encoder.WriteStart("span"))
				err := context.Recurse(dec)
				context.check(context.Encoder.WriteEnd("span"))
				context.check(context.Encoder.WriteEnd("div"))
				return err
			},
			"menucascade": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				start.Name.Local = "span"

				setAttr(&start, "class", "menucascade")
				// encode starting tag and attributes
				if err := context.Encoder.Encode(start); err != nil {
					return err
				}

				first := true

				// recurse on child tokens
				for {
					token, err := dec.Token()
					if err != nil {
						if err == io.EOF {
							return nil
						}
						return err
					}

					if _, ended := token.(xml.EndElement); ended {
						break
					}
					if _, starting := token.(xml.StartElement); starting {
						if !first {
							context.Encoder.WriteRaw("&gt;")
						}
						first = false
					}
					if err := context.Handle(dec, token); err != nil {
						return err
					}
				}

				// always encode ending tag
				context.check(context.Encoder.Encode(xml.EndElement{start.Name}))

				return nil
			},

			"ui-item-name": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				start.Name.Local = "dt"

				setAttr(&start, "class", "ui-item-name")
				// encode starting tag and attributes
				if err := context.Encoder.Encode(start); err != nil {
					return err
				}

				first := true

				// recurse on child tokens
				for {
					token, err := dec.Token()
					if err != nil {
						if err == io.EOF {
							return nil
						}
						return err
					}

					if _, ended := token.(xml.EndElement); ended {
						break
					}
					if _, starting := token.(xml.StartElement); starting {
						if !first {
							context.Encoder.WriteRaw(", ")
						}
						first = false
					}
					if err := context.Handle(dec, token); err != nil {
						return err
					}
				}

				// always encode ending tag
				context.check(context.Encoder.Encode(xml.EndElement{start.Name}))

				return nil
			},

			"simpletable": HandleSimpleTable,
			"table":       HandleTable,

			"step": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				start.Name.Local = "li"

				context.check(context.Encoder.Encode(start))
				if getAttr(&start, "importance") == "optional" {
					context.Encoder.WriteRaw("(Optional) ")
				}
				err := context.Recurse(dec)
				context.check(context.Encoder.Encode(xml.EndElement{start.Name}))

				return err
			},
			"substep": func(context *Context, dec *xml.Decoder, start xml.StartElement) error {
				start.Name.Local = "li"

				context.check(context.Encoder.Encode(start))
				if getAttr(&start, "importance") == "optional" {
					context.Encoder.WriteRaw("(Optional) ")
				}
				err := context.Recurse(dec)
				context.check(context.Encoder.Encode(xml.EndElement{start.Name}))

				return err
			},
		},
	}
}