// sample usage for parse stylesheet func ExampleParseStylesheet() { //parse the stylesheet style, _ := xml.ReadFile("testdata/test.xsl", xml.StrictParseOption) stylesheet, _ := ParseStylesheet(style, "testdata/test.xsl") //process the input input, _ := xml.ReadFile("testdata/test.xml", xml.StrictParseOption) output, _ := stylesheet.Process(input, StylesheetOptions{false, nil}) fmt.Println(output) }
func (context *ExecutionContext) FetchInputDocument(loc string, relativeToSource bool) (doc *xml.XmlDocument) { //create the map if needed if context.InputDocuments == nil { context.InputDocuments = make(map[string]*xml.XmlDocument) } // rely on caller to tell us how to resolve relative paths base := "" if relativeToSource { base, _ = filepath.Abs(filepath.Dir(context.Source.Uri())) } else { base, _ = filepath.Abs(filepath.Dir(context.Style.Doc.Uri())) } resolvedLoc := filepath.Join(base, loc) //if abspath in map return existing document doc, ok := context.InputDocuments[resolvedLoc] if ok { return } //else load the document and add to map doc, e := xml.ReadFile(resolvedLoc, xml.StrictParseOption) if e != nil { fmt.Println(e) return } context.InputDocuments[resolvedLoc] = doc return }
// Helper where actual checking occurs func runXslTest(t *testing.T, xslFile, inputXmlFile, outputXmlFile string) bool { style, _ := xml.ReadFile(xslFile, xml.StrictParseOption) input, _ := xml.ReadFile(inputXmlFile, xml.StrictParseOption) outData, _ := ioutil.ReadFile(outputXmlFile) expected := string(outData) stylesheet, _ := ParseStylesheet(style, xslFile) testOptions := StylesheetOptions{false, nil} output, _ := stylesheet.Process(input, testOptions) if output != expected { t.Error(xslFile, "failed") fmt.Println("---- EXPECTED ", xslFile, "----") fmt.Println(expected) fmt.Println("---- ACTUAL ", xslFile, "----") fmt.Println(output) return false } return true }
func main() { flag.Usage = usage flag.Parse() if flag.NArg() < 2 { usage() return } //set some prefs based on flags xslfile := flag.Arg(0) inxml := flag.Arg(1) style, err := xml.ReadFile(xslfile, xml.StrictParseOption) if err != nil { fmt.Println(err) return } doc, err := xml.ReadFile(inxml, xml.StrictParseOption) if err != nil { fmt.Println(err) return } //TODO: register some extensions (EXSLT, testing, debug) //TODO: process XInclude if enabled stylesheet, err := xslt.ParseStylesheet(style, xslfile) if err != nil { fmt.Println(err) return } options := xslt.StylesheetOptions{*indent, nil} output, err := stylesheet.Process(doc, options) if err != nil { fmt.Println(err) return } fmt.Println(output) }
// Creates an xlstTransform from file specified by path. func newXsltTransform(path string) (*xsltTransform, error) { doc, err := xml.ReadFile(path, xml.StrictParseOption) if err != nil { return nil, err } stylesheet, err := xslt.ParseStylesheet(doc, path) if err != nil { doc.Free() return nil, err } result := new(xsltTransform) result.stylesheet = stylesheet return result, nil }
// Runs the transformation on the given input, returning an output as a byte // slice. func (transform *xsltTransform) Process(input []byte) ([]byte, error) { // gokogiri can automatically determine the encoding when parsing a // file, but not when loading from memory. Save to a temporary file until // a better method can be found. file, err := ioutil.TempFile(os.TempDir(), "ftxlstin") if err != nil { return nil, err } defer os.Remove(file.Name()) _, err = file.Write(input) if err != nil { return nil, err } doc, err := xml.ReadFile(file.Name(), xml.StrictParseOption) if err != nil { return nil, err } defer doc.Free() options := xslt.StylesheetOptions{false, nil} output, err := transform.stylesheet.Process(doc, options) if err != nil { return nil, err } return []byte(output), nil }
// Here we iterate through the children; this has been moved to its own function // to facilitate the implementation of xsl:include (where we want the children to // be treated as if they were part of the calling stylesheet) func (style *Stylesheet) parseChildren(root xml.Node, fileuri string) (err error) { //iterate through children for cur := root.FirstChild(); cur != nil; cur = cur.NextSibling() { //skip blank nodes if IsBlank(cur) { continue } //skip comment nodes if cur.NodeType() == xml.XML_COMMENT_NODE { continue } //handle templates if IsXsltName(cur, "template") { style.ParseTemplate(cur) continue } if IsXsltName(cur, "variable") { style.RegisterGlobalVariable(cur) continue } if IsXsltName(cur, "key") { name := cur.Attr("name") use := cur.Attr("use") match := cur.Attr("match") k := &Key{make(map[string]xml.Nodeset), use, match} style.Keys[name] = k continue } //TODO: this is cheating. Also note global params can have their // value overwritten if IsXsltName(cur, "param") { style.RegisterGlobalVariable(cur) continue } if IsXsltName(cur, "attribute-set") { style.RegisterAttributeSet(cur) continue } if IsXsltName(cur, "include") { //check for recursion, multiple includes loc := cur.Attr("href") base := path.Dir(fileuri) loc = path.Join(base, loc) _, already := style.includes[loc] if already { panic("Multiple include detected of " + loc) } style.includes[loc] = true //load the stylesheet doc, e := xml.ReadFile(loc, xml.StrictParseOption) if e != nil { fmt.Println(e) err = e return } //_, _ = ParseStylesheet(doc, loc) //update the including stylesheet e = style.parseChildren(doc.Root(), loc) if e != nil { fmt.Println(e) err = e return } continue } if IsXsltName(cur, "import") { //check for recursion, multiple includes loc := cur.Attr("href") base := path.Dir(fileuri) loc = path.Join(base, loc) _, already := style.includes[loc] if already { panic("Multiple include detected of " + loc) } style.includes[loc] = true //increment import; new style context doc, _ := xmlReadFile(loc) _import, _ := ParseStylesheet(doc, loc) style.Imports.PushFront(_import) continue } if IsXsltName(cur, "output") { cdata := cur.Attr("cdata-section-elements") if cdata != "" { style.CDataElements = strings.Fields(cdata) } style.OutputMethod = cur.Attr("method") omit := cur.Attr("omit-xml-declaration") if omit == "yes" { style.OmitXmlDeclaration = true } indent := cur.Attr("indent") if indent == "yes" { style.IndentOutput = true } standalone := cur.Attr("standalone") if standalone == "yes" { style.Standalone = true } encoding := cur.Attr("encoding") if encoding != "" && encoding != "utf-8" { //TODO: emit a warning if we do not support the encoding // if unsupported, leave blank to output default UTF-8 style.DesiredEncoding = encoding } style.doctypeSystem = cur.Attr("doctype-system") style.doctypePublic = cur.Attr("doctype-public") continue } if IsXsltName(cur, "strip-space") { el := cur.Attr("elements") if el != "" { style.StripSpace = strings.Fields(el) } continue } if IsXsltName(cur, "preserve-space") { el := cur.Attr("elements") if el != "" { style.PreserveSpace = strings.Fields(el) } continue } if IsXsltName(cur, "namespace-alias") { stylens := cur.Attr("stylesheet-prefix") resns := cur.Attr("result-prefix") style.NamespaceAlias[stylens] = resns continue } if IsXsltName(cur, "decimal-format") { fmt.Println("GLOBAL TODO ", cur.Name()) continue } } return }