func (e *LiteralResultElement) Compile(node xml.Node) { for cur := node.FirstChild(); cur != nil; cur = cur.NextSibling() { res := CompileSingleNode(cur) if res != nil { res.Compile(cur) e.Children = append(e.Children, res) } } }
// Compile the variable. // // TODO: compile the XPath expression and determine if it is a constant func (i *Variable) Compile(node xml.Node) { i.Name = i.Node.Attr("name") for cur := node.FirstChild(); cur != nil; cur = cur.NextSibling() { res := CompileSingleNode(cur) if res != nil { res.Compile(cur) i.Children = append(i.Children, res) } } }
func (template *Template) CompileContent(node xml.Node) { //parse the content and register the match pattern for cur := node.FirstChild(); cur != nil; cur = cur.NextSibling() { res := CompileSingleNode(cur) if res != nil { res.Compile(cur) template.AddChild(res) } } }
// ChildrenOf returns the node children, ignoring any whitespace-only text nodes that // are stripped by strip-space or xml:space func (context *ExecutionContext) ChildrenOf(node xml.Node) (children []xml.Node) { for cur := node.FirstChild(); cur != nil; cur = cur.NextSibling() { //don't count stripped nodes if context.ShouldStrip(cur) { continue } children = append(children, cur) } return }
// Compile the instruction. // // TODO: we should validate the structure during this step func (i *XsltInstruction) Compile(node xml.Node) { for cur := node.FirstChild(); cur != nil; cur = cur.NextSibling() { res := CompileSingleNode(cur) if cur.Name() == "sort" && cur.Namespace() == XSLT_NAMESPACE { i.sorting = append(i.sorting, compileSortFunction(res.(*XsltInstruction))) continue } if res != nil { res.Compile(cur) i.Children = append(i.Children, res) } } }
func (i *XsltInstruction) copyToOutput(node xml.Node, context *ExecutionContext, recursive bool) { switch node.NodeType() { case xml.XML_TEXT_NODE: if context.UseCDataSection(context.OutputNode) { r := context.Output.CreateCDataNode(node.Content()) context.OutputNode.AddChild(r) } else { r := context.Output.CreateTextNode(node.Content()) context.OutputNode.AddChild(r) } case xml.XML_ATTRIBUTE_NODE: aname := node.Name() ahref := node.Namespace() val := node.Content() if ahref == "" { context.OutputNode.SetAttr(aname, val) } else { context.OutputNode.SetNsAttr(ahref, aname, val) } case xml.XML_COMMENT_NODE: r := context.Output.CreateCommentNode(node.Content()) context.OutputNode.AddChild(r) case xml.XML_PI_NODE: name := node.Attr("name") r := context.Output.CreatePINode(name, node.Content()) context.OutputNode.AddChild(r) case xml.XML_NAMESPACE_DECL: //in theory this should work //in practice it's a little complicated due to the fact //that namespace declarations don't map to the node type //very well //will need to revisit //context.OutputNode.DeclareNamespace(node.Name(), node.Content()) case xml.XML_ELEMENT_NODE: aname := node.Name() r := context.Output.CreateElementNode(aname) context.OutputNode.AddChild(r) ns := node.Namespace() if ns != "" { //TODO: search through namespaces in-scope prefix, _ := context.Style.NamespaceMapping[ns] r.SetNamespace(prefix, ns) } else { //may need to explicitly reset to empty namespace def := context.DefaultNamespace(context.OutputNode) if def != "" { r.SetNamespace("", "") } } //copy namespace declarations for _, decl := range node.DeclaredNamespaces() { r.DeclareNamespace(decl.Prefix, decl.Uri) } old := context.OutputNode context.OutputNode = r if recursive { //copy attributes for _, attr := range node.Attributes() { i.copyToOutput(attr, context, recursive) } for cur := node.FirstChild(); cur != nil; cur = cur.NextSibling() { i.copyToOutput(cur, context, recursive) } } context.OutputNode = old case xml.XML_DOCUMENT_NODE: if recursive { for cur := node.FirstChild(); cur != nil; cur = cur.NextSibling() { i.copyToOutput(cur, context, recursive) } } } }
// 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 }