示例#1
0
        protected void addTag(Tag tag, Dictionary<string, string> cleanAttributes, Dictionary<string, object> tagProperties)
        {
            // Used to add a tag to the stack.  Various properties can be passed in the dictionary
            // as being information required by the tag.
            // Currently supported properties are:
            //  'command'         - The (command,args) tuple associated with this command
            //  'originalAtts'    - The original attributes that include any metal/tal attributes
            //  'endTagSymbol'    - The symbol associated with the end tag for this element
            //  'popFunctionList' - A list of functions to execute when this tag is popped
            //  'singletonTag'    - A boolean to indicate that this is a singleton flag

            tag.Attributes = cleanAttributes;

            // Add the tag to the tagStack (list of tuples (tag, properties, useMacroLocation))

            TALCommand command = (TALCommand)(tagProperties.ContainsKey("command") ? tagProperties["command"] : null);
            Dictionary<string, string> originalAtts = (Dictionary<string, string>)(tagProperties.ContainsKey("originalAtts") ? tagProperties["originalAtts"] : null);
            int singletonTag = (int)(tagProperties.ContainsKey("singletonTag") ? tagProperties["singletonTag"] : 0);

            TagInfo ti = new TagInfo();
            if (command != null)
            {
                if (command.ID == Constants.METAL_USE_MACRO)
                {
                    ti.Tag = tag;
                    ti.Properties = tagProperties;
                    ti.UseMacroLocation = this.commandList.Count + 1;
                }
                else
                {
                    ti.Tag = tag;
                    ti.Properties = tagProperties;
                    ti.UseMacroLocation = -1;
                }
            }
            else
            {
                ti.Tag = tag;
                ti.Properties = tagProperties;
                ti.UseMacroLocation = -1;
            }
            this.tagStack.Add(ti);

            if (command != null)
            {
                // All tags that have a TAL attribute on them start with a 'start scope'
                TALCommand cmd = new TALCommand();
                cmd.Tag = this.currentStartTag;
                cmd.ID = Constants.TAL_START_SCOPE;
                cmd.Attributes = new List<object>();
                cmd.Attributes.Add(originalAtts);
                cmd.Attributes.Add(cleanAttributes);
                this.AddCommand(cmd);
                // Now we add the TAL command
                this.AddCommand(command);
            }
            else
            {
                // It's just a straight output, so create an output command and append it
                TALCommand cmd = new TALCommand();
                cmd.Tag = this.currentStartTag;
                cmd.ID = Constants.TAL_OUTPUT;
                cmd.Attributes = new List<object>();
                cmd.Attributes.Add(this.tagAsText(tag, singletonTag));
                this.AddCommand(cmd);
            }
        }
示例#2
0
 public TemplateParseException(Tag tag, string errorDescription)
     : base(errorDescription)
 {
     this.m_Tag = tag;
     this.m_ErrorDescription = errorDescription;
 }
示例#3
0
        public TALProgram Compile(string source, string sourcePath)
        {
            // Initialise a template compiler.
            this.commandList = new List<TALCommand>();
            this.tagStack = new List<TagInfo>();
            this.symbolLocationTable = new Dictionary<int, int>();
            this.macroMap = new Dictionary<string, TALSubProgram>();
            this.imports = new HashSet<string>();
            this.endTagSymbol = 1;
            this.currentStartTag = null;

            XmlReader reader = null;
            StringReader inputReader = null;
            try
            {
                inputReader = new StringReader(source);
                XmlTextReader xmlTextReader = new XmlTextReader(inputReader);
                xmlTextReader.XmlResolver = null;
                xmlTextReader.Namespaces = false;

                XmlReaderSettings readerSettings = new XmlReaderSettings();
                readerSettings.ProhibitDtd = false;

                reader = XmlReader.Create(xmlTextReader, readerSettings);
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        Tag tag = new Tag();
                        tag.SourcePath = sourcePath;
                        IXmlLineInfo li = reader as IXmlLineInfo;
                        if (li != null && li.HasLineInfo())
                        {
                            tag.LineNumber = li.LineNumber;
                            tag.LinePosition = li.LinePosition;
                        }
                        tag.Name = reader.Name;
                        tag.Attributes = new Dictionary<string, string>();
                        string atttribs = "";
                        for (int i = 0; i < reader.AttributeCount; i++)
                        {
                            reader.MoveToAttribute(i);
                            atttribs += string.Format(" {0}=\"{1}\"", reader.Name, reader.Value);
                            tag.Attributes.Add(reader.Name, reader.Value);
                        }
                        reader.MoveToElement();
                        if (reader.IsEmptyElement)
                        {
                            handle_startendtag(tag);
                        }
                        else
                        {
                            handle_starttag(tag);
                        }
                    }
                    else if (reader.NodeType == XmlNodeType.EndElement)
                    {
                        Tag tag = new Tag();
                        tag.SourcePath = sourcePath;
                        IXmlLineInfo li = reader as IXmlLineInfo;
                        if (li != null && li.HasLineInfo())
                        {
                            tag.LineNumber = li.LineNumber;
                            tag.LinePosition = li.LinePosition;
                        }
                        tag.Name = reader.Name;
                        handle_endtag(tag);
                    }
                    else if (reader.NodeType == XmlNodeType.DocumentType)
                    {
                        handle_doctype(reader);
                    }
                    else if (reader.NodeType == XmlNodeType.Comment)
                    {
                        handle_comment(reader.Value);
                    }
                    else if (reader.NodeType == XmlNodeType.CDATA)
                    {
                        handle_cdata(reader.Value);
                    }
                    else if (reader.NodeType == XmlNodeType.XmlDeclaration)
                    {
                        handle_xmldecl(reader.Name, reader.Value);
                    }
                    else if (reader.NodeType == XmlNodeType.Whitespace ||
                        reader.NodeType == XmlNodeType.SignificantWhitespace ||
                        reader.NodeType == XmlNodeType.Text)
                    {
                        handle_data(reader.Value);
                    }
                    else if (reader.NodeType == XmlNodeType.ProcessingInstruction)
                    {
                        handle_pi(reader.Name, reader.Value);
                    }
                    else if (reader.NodeType == XmlNodeType.EntityReference)
                    {
                        handle_entityref(reader.Name);
                    }
                }
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                if (inputReader != null)
                    inputReader.Close();
            }

            TALProgram template = new TALProgram(source, sourcePath, this.commandList, this.macroMap, this.imports, this.symbolLocationTable);
            return template;
        }
示例#4
0
 public string tagAsText(Tag tag, int singletonFlag)
 {
     // This returns a tag as text.
     //
     string result = "<";
     result += tag.Name;
     foreach (KeyValuePair<string, string> att in tag.Attributes)
     {
         result += " ";
         result += att.Key;
         result += "=\"";
         result += Utils.EscapeXml(att.Value, true);
         result += "\"";
     }
     if (singletonFlag == 1)
         result += " />";
     else
         result += ">";
     return result;
 }
示例#5
0
 protected void popTag(Tag tag)
 {
     popTag(tag, 0);
 }
示例#6
0
        protected void popTag(Tag tag, int omitTagFlag)
        {
            // omitTagFlag is used to control whether the end tag should be included in the
            // output or not.  In HTML 4.01 there are several tags which should never have
            // end tags, this flag allows the template compiler to specify that these
            // should not be output.

            while (this.tagStack.Count > 0)
            {
                TagInfo ti = this.tagStack[this.tagStack.Count - 1];
                this.tagStack.RemoveAt(this.tagStack.Count - 1);

                Tag oldTag = ti.Tag;
                Dictionary<string, object> tagProperties = ti.Properties;

                int? endTagSymbol = (int?)(tagProperties.ContainsKey("endTagSymbol") ? tagProperties["endTagSymbol"] : null);
                List<VoidFuncDelegate> popCommandList = (List<VoidFuncDelegate>)(tagProperties.ContainsKey("popCommandList") ? tagProperties["popCommandList"] : null);
                int singletonTag = (int)(tagProperties.ContainsKey("singletonTag") ? tagProperties["singletonTag"] : 0);

                if (popCommandList != null)
                {
                    foreach (VoidFuncDelegate func in popCommandList)
                    {
                        func();
                    }
                }

                if (oldTag.Name == tag.Name)
                {
                    // We've found the right tag, now check to see if we have any TAL commands on it
                    if (endTagSymbol != null)
                    {
                        // We have a command (it's a TAL tag)
                        // Note where the end tag symbol should point (i.e. the next command)
                        this.symbolLocationTable[(int)endTagSymbol] = this.commandList.Count;

                        // We need a "close scope and tag" command
                        TALCommand cmd = new TALCommand();
                        cmd.Tag = this.currentStartTag;
                        cmd.ID = Constants.TAL_ENDTAG_ENDSCOPE;
                        cmd.Attributes = new List<object>();
                        cmd.Attributes.Add(tag.Name);
                        cmd.Attributes.Add(omitTagFlag);
                        cmd.Attributes.Add(singletonTag);
                        this.AddCommand(cmd);
                        return;
                    }
                    else if (omitTagFlag == 0 && singletonTag == 0)
                    {
                        // We are popping off an un-interesting tag, just add the close as text
                        // We need a "close scope and tag" command
                        TALCommand cmd = new TALCommand();
                        cmd.Tag = this.currentStartTag;
                        cmd.ID = Constants.TAL_OUTPUT;
                        cmd.Attributes = new List<object>();
                        cmd.Attributes.Add("</" + tag.Name + ">");
                        this.AddCommand(cmd);
                        return;
                    }
                    else
                    {
                        // We are suppressing the output of this tag, so just return
                        return;
                    }
                }
                else
                {
                    // We have a different tag, which means something like <br> which never closes is in
                    // between us and the real tag.

                    // If the tag that we did pop off has a command though it means un-balanced TAL tags!
                    if (endTagSymbol != null)
                    {
                        // ERROR
                        string msg = string.Format("TAL/METAL Elements must be balanced - found close tag {0} expecting {1}", tag.Name, oldTag.Name);
                        throw new TemplateParseException(oldTag, msg);
                    }
                }
            }
            throw new TemplateParseException(null,
                string.Format("</{0}> {1}", tag.Name, "Close tag encountered with no corresponding open tag."));
        }
示例#7
0
 protected void parseStartTag(Tag tag, Dictionary<string, string> attributes)
 {
     parseStartTag(tag, attributes, 0);
 }
示例#8
0
        protected void parseStartTag(Tag tag, Dictionary<string, string> attributes, int singletonElement)
        {
            // Note down the tag we are handling, it will be used for error handling during
            // compilation
            this.currentStartTag = new Tag();
            this.currentStartTag.Name = tag.Name;
            this.currentStartTag.Attributes = attributes;
            this.currentStartTag.SourcePath = tag.SourcePath;
            this.currentStartTag.LineNumber = tag.LineNumber;
            this.currentStartTag.LinePosition = tag.LinePosition;

            // Look for tal/metal attributes
            List<int> foundTALAtts = new List<int>();
            List<int> foundMETALAtts = new List<int>();
            Dictionary<int, string> foundCommandsArgs = new Dictionary<int, string>();
            Dictionary<string, string> cleanAttributes = new Dictionary<string, string>();
            Dictionary<string, string> originalAttributes = new Dictionary<string, string>();
            Dictionary<string, object> tagProperties = new Dictionary<string, object>();
            List<VoidFuncDelegate> popTagFuncList = new List<VoidFuncDelegate>();
            bool isTALElementNameSpace = false;
            string prefixToAdd = "";
            tagProperties.Add("singletonTag", singletonElement);

            // Determine whether this element is in either the METAL or TAL namespace
            if (tag.Name.IndexOf(':') > 0)
            {
                // We have a namespace involved, so let's look to see if its one of ours
                string _namespace = tag.Name.Substring(0, tag.Name.IndexOf(':'));
                if (_namespace == this.metal_namespace_prefix)
                {
                    isTALElementNameSpace = true;
                    prefixToAdd = this.metal_namespace_prefix + ":";
                }
                else if (_namespace == this.tal_namespace_prefix)
                {
                    // This tag has not his own scope
                    if (tag.Name == tal_namespace_omitscope)
                    {
                        tag.OmitTagScope = true;
                        this.currentStartTag.OmitTagScope = true;
                    }
                    isTALElementNameSpace = true;
                    prefixToAdd = this.tal_namespace_prefix + ":";
                }
                if (isTALElementNameSpace)
                {
                    // We should treat this an implicit omit-tag
                    foundTALAtts.Add(Constants.TAL_OMITTAG);
                    // Will go to default, i.e. yes
                    foundCommandsArgs[Constants.TAL_OMITTAG] = "";
                }
            }

            foreach (KeyValuePair<string, string> attr in attributes)
            {
                string att = attr.Key;
                string value = attr.Value;

                string commandAttName = "";

                originalAttributes.Add(att, value);
                if (isTALElementNameSpace && !(att.IndexOf(':') > 0))
                {
                    // This means that the attribute name does not have a namespace, so use the prefix for this tag.
                    commandAttName = prefixToAdd + att;
                }
                else
                {
                    commandAttName = att;
                }

                if (att.Length > 4 && att.Substring(0, 5) == "xmlns")
                {
                    // We have a namespace declaration.
                    string prefix = att.Length > 5 ? att.Substring(6) : "";
                    if (value == Constants.METAL_NAME_URI)
                    {
                        // It's a METAL namespace declaration
                        if (prefix.Length > 0)
                        {
                            this.metal_namespace_prefix_stack.Add(this.metal_namespace_prefix);
                            this.setMETALPrefix(prefix);
                            // We want this function called when the scope ends
                            popTagFuncList.Add(this.popMETALNamespace);
                        }
                        else
                        {
                            // We don't allow METAL/TAL to be declared as a default
                            string msg = "Can not use METAL name space by default, a prefix must be provided.";
                            throw new TemplateParseException(this.currentStartTag, msg);
                        }
                    }
                    else if (value == Constants.TAL_NAME_URI)
                    {
                        // TAL this time
                        if (prefix.Length > 0)
                        {
                            this.tal_namespace_prefix_stack.Add(this.tal_namespace_prefix);
                            this.setTALPrefix(prefix);
                            // We want this function called when the scope ends
                            popTagFuncList.Add(this.popTALNamespace);
                        }
                        else
                        {
                            // We don't allow METAL/TAL to be declared as a default
                            string msg = "Can not use TAL name space by default, a prefix must be provided.";
                            throw new TemplateParseException(this.currentStartTag, msg);
                        }
                    }
                    else
                    {
                        // It's nothing special, just an ordinary namespace declaration
                        cleanAttributes.Add(att, value);
                    }
                }
                else if (this.tal_attribute_map.ContainsKey(commandAttName))
                {
                    // It's a TAL attribute
                    int cmnd = this.tal_attribute_map[commandAttName];
                    if (cmnd == Constants.TAL_OMITTAG && isTALElementNameSpace)
                    {
                        //this.log.warn("Supressing omit-tag command present on TAL or METAL element");
                    }
                    else
                    {
                        foundCommandsArgs.Add(cmnd, value);
                        foundTALAtts.Add(cmnd);
                    }
                }
                else if (this.metal_attribute_map.ContainsKey(commandAttName))
                {
                    // It's a METAL attribute
                    int cmnd = this.metal_attribute_map[commandAttName];
                    foundCommandsArgs.Add(cmnd, value);
                    foundMETALAtts.Add(cmnd);
                }
                else
                {
                    cleanAttributes.Add(att, value);
                }
            }
            tagProperties.Add("popFunctionList", popTagFuncList);

            // This might be just content
            if ((foundTALAtts.Count + foundMETALAtts.Count) == 0)
            {
                // Just content, add it to the various stacks
                this.addTag(tag, cleanAttributes, tagProperties);
                return;
            }

            // Create a symbol for the end of the tag - we don't know what the offset is yet
            this.endTagSymbol += 1;
            tagProperties.Add("endTagSymbol", this.endTagSymbol);

            // Sort the METAL commands by priority. Priority is defined by opcode number, see Constants.METAL_* opcodes.
            foundMETALAtts.Sort();

            // Sort the TAL commands by priority. Priority is defined by opcode number, see Constants.TAL_* opcodes.
            foundTALAtts.Sort();

            // We handle the METAL before the TAL
            List<int> allCommands = new List<int>();
            allCommands.AddRange(foundMETALAtts);
            allCommands.AddRange(foundTALAtts);
            int firstTag = 1;
            foreach (int talAtt in allCommands)
            {
                // Parse and create a command for each
                TALCommand cmnd = this.commandHandler[talAtt](foundCommandsArgs[talAtt]);
                if (cmnd != null)
                {
                    if (firstTag == 1)
                    {
                        // The first one needs to add the tag
                        firstTag = 0;
                        tagProperties["originalAtts"] = originalAttributes;
                        tagProperties["command"] = cmnd;
                        this.addTag(tag, cleanAttributes, tagProperties);
                    }
                    else
                    {
                        // All others just append
                        this.AddCommand(cmnd);
                    }
                }
            }

            TALCommand cmd = new TALCommand();
            cmd.Tag = this.currentStartTag;
            cmd.ID = Constants.TAL_STARTTAG;
            cmd.Attributes = new List<object>();
            cmd.Attributes.Add(tag);
            cmd.Attributes.Add(singletonElement);

            if (firstTag == 1)
            {
                tagProperties["originalAtts"] = originalAttributes;
                tagProperties["command"] = cmd;
                this.addTag(tag, cleanAttributes, tagProperties);
            }
            else
            {
                // Add the start tag command in as a child of the last TAL command
                this.AddCommand(cmd);
            }
        }
示例#9
0
 protected void parseEndTag(Tag tag)
 {
     // Just pop the tag and related commands off the stack.
     this.popTag(tag);
 }
示例#10
0
        protected void handle_starttag(Tag tag, int singletonElement)
        {
            Dictionary<string, string> atts = new Dictionary<string, string>();

            foreach (KeyValuePair<string, string> attInfo in tag.Attributes)
            {
                string att = attInfo.Key;
                string attValue = attInfo.Value;

                // We need to spot empty tal:omit-tags
                if (attValue == null)
                {
                    if (att == this.tal_namespace_omittag)
                        atts.Add(att, "");
                    else
                        atts.Add(att, att);
                }
                else
                {
                    // Expand any SGML entity references
                    if (attValue.IndexOf('&') != -1 && attValue.IndexOf('&') < attValue.LastIndexOf(';'))
                    {
                        foreach (string entity in SGMLEntityNames.htmlNameToUnicodeNumber.Keys)
                        {
                            if (attValue.Contains(entity))
                            {
                                attValue = attValue.Replace(entity, ((char)SGMLEntityNames.htmlNameToUnicodeNumber[entity]).ToString());
                            }
                        }
                    }
                    atts.Add(att, attValue);
                }
            }

            if (Constants.HTML_FORBIDDEN_ENDTAG.ContainsKey(tag.Name.ToUpper()))
            {
                // This should have no end tag, so we just do the start and suppress the end
                this.parseStartTag(tag, atts, singletonElement);
                this.popTag(tag, 1);
            }
            else
                this.parseStartTag(tag, atts, singletonElement);
        }
示例#11
0
 protected void handle_starttag(Tag tag)
 {
     handle_starttag(tag, 0);
 }
示例#12
0
 protected void handle_startendtag(Tag tag)
 {
     this.handle_starttag(tag, 1);
     if (!Constants.HTML_FORBIDDEN_ENDTAG.ContainsKey(tag.Name.ToUpper()))
         this.handle_endtag(tag);
 }
示例#13
0
 protected void handle_endtag(Tag tag)
 {
     if (Constants.HTML_FORBIDDEN_ENDTAG.ContainsKey(tag.Name.ToUpper()))
     {
         //this.log.warn(string.Format("HTML 4.01 forbids end tags for the {0} element", tag));
     }
     else
     {
         // Normal end tag
         this.popTag(tag);
     }
 }