SitePoint Sponsor

User Tag List

Results 1 to 10 of 10
  1. #1
    SitePoint Guru
    Join Date
    Nov 2004
    Location
    England
    Posts
    702
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    Question Pseudo HTML Code. Possible? Advisable?

    As part of a CMS that I'm always working on, I had an idea. It's most likely one that has been around for years, but I've only just hit upon it.

    Each page can be one of the following:

    • HTML code stored in the database
    • a PHP page that is included
    • a forwarder, usually that does some work (ie form submission) and then redirects you elsewhere. Also used to track links etc

    So, if I want to allow people to put dynamic code in, via a webpanel, how can I do it, seeing as how I can't save PHP code in to the database and execute it later?

    I had the idea of providing certain HTML-like tags that can be used by the person creating the page. In a WYSIWYG editor you would see nothing but a placeholder, but when you view the page you will see dynamic and new content.

    An example of this in use would be with RSS feeds. Each module on the system outputs data in an RSS format for use either in an RSS reader of some kind, or elsewhere on the site. Each RSS feed is installed in the database and a user could pick from these as they are allowed (via the permissions system).

    Lets say that we have a feed called "Popular Items" on a shopping site. This feed will contain details on a number of the most commonly purchased items. Lets say 20 for the sake of argument. Now, on a page that the administrator wants to use some of this feed on, he/she would enter something like:

    Code:
    <feed start="1" end="10" id="popitems">Popular Items</feed>
    It's not forced to be exactly like that, but I'm sure you get the idea. With this particular example, the <feed> tags would be identified by PHP and the CMS would know that it needs to be working with an RSS feed. The description between the tags tells it which one to load from the database. The start and end values in the opening tag are passed to the function that processes the feed and generates the actual output. Obviously the id can be used for various things as an id can be with any real HTML tags.

    The function (lets say cms_include_feed($feed, $start, $end, $id) for now eh?) will now know that it is only to show items from 1 to 10, and will wrap them all in a <div> with the id "popitems".

    Now, if that makes sense, then how am I best to go about it? I assume regex is the way to go, but I've never had much luck with that. I have a few other tags that I want to use to allow various details to be included, but once I've worked out the feed example I reckon I can work the rest out easily enough. What do you guys think?

  2. #2
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    I've used such a system and didn't find that many pitfalls to be honest, you just use xHTML for the rest of the template and create custom elements.

    You then just use DOMDocument (Not RegExp. ) to load the template, extract the relevant nodes and repopulate said node with its xHTML equivalent.

    I found it very extensible indeed.
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  3. #3
    . shoooo... silver trophy logic_earth's Avatar
    Join Date
    Oct 2005
    Location
    CA
    Posts
    9,013
    Mentioned
    8 Post(s)
    Tagged
    0 Thread(s)
    Or alternatively to using PHP and the DOM can utilize XML and XSLT to transform the data/template into HTML or any other format you wish. Simplistic XML template:

    Code XML:
    <?xml version="1.0" encoding="utf-8"?>
    <document>
    	<title>This is my title.</title>
    	<navigation>
    		<item href="...">Link A</item>
    		<item href="...">Link B</item>
    		<item href="...">Link C</item>
    	</navigation>
    	<content>
    		<![CDATA[
    			<h2>This is my header</h2>
    			<p>la la la la la la la</p>
    				<h3>Another header</h3>
    				<p>mew mew mew mew mew</p>
    					<h4>...</h4>
    					<p>...</p>
    			<h2>...</h2>
    			<p>...</p>
    		]]>
    	</content>
    	<sidebar>
    		<content><![CDATA[...]]></content>
    	</sidebar>
    </document>
    Logic without the fatal effects.
    All code snippets are licensed under WTFPL.


  4. #4
    SitePoint Guru
    Join Date
    Nov 2004
    Location
    England
    Posts
    702
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Hmm, XHTML? I already have a templating system that works well and I don't want to tamper with that, and I'm avoiding XHTML for various reasons (discussed in the HTML forums here). All I need is to replace these 'tags' with the relevant code. I'll look at DOMDocument, but I've never used it. Any tips?

  5. #5
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    I'm not entirely sure we're discussing the same thing....If memory serves, it went something like...

    PHP Code:
    <?php
    interface ITemplateElement
    {
        public function 
    render();
    }

    abstract class 
    TemplateElement
    {
        protected 
    $oElement;
        
        public function 
    __construct(DOMElement $oElement)
        {
            
    $this->oElement $oElement;
        }
    }

    class 
    CSS extends TemplateElement implements ITemplateElement
    {
        public function 
    render()
        {
            return 
    sprintf('<link type="text/css" rel="stylesheet" href="%s" />',
                
    $this->oElement->getAttribute('source')
            );
        }
    }
    ?>
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  6. #6
    SitePoint Guru
    Join Date
    Nov 2004
    Location
    England
    Posts
    702
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Hmm, we may not be on the same page, I'm not sure. Basically I just want to be able to replace some text in the body of the page (which is from a MySQL database, in a variable, lets say $body) with something else, but it's not a simple str_replace(). The user would probably write something like this:

    HTML Code:
    ...<body>
    <p>Here is some text, and here is my feed:</p>
    <feed start="1" end="10" id="feedid">Feed Name</feed>
    <p>And now is some more text</p>
    </body>...
    Is that what you think I mean? Or have I confused things further?

  7. #7
    SitePoint Evangelist simshaun's Avatar
    Join Date
    Apr 2008
    Location
    North Carolina
    Posts
    438
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yea, you can use DOMDocument (or RegExp with a callback) for that.

    For DOMDocument and possibly RegEx as well, this article may be of help.
    If you decide to do it the RegEx way, then you'll probably be using preg_replace_callback
    Last edited by simshaun; Feb 3, 2009 at 15:44.

  8. #8
    SitePoint Guru
    Join Date
    Nov 2004
    Location
    England
    Posts
    702
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    OK thanks, I'll take a look at that when I have an hour to spare.

    I'm loving the fact that nobody is saying "stupid idea" just yet too

  9. #9
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    996
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    I recently did something similar to this.

    I have lots of potential markup:

    HTML Code:
    <div>
    <format type="floor">3.1415</format>
    <format type="ceil">3.1415</format>
    
    <date>2009-02-03 21:50</date>
    
    
    <text id="GET_HELP" />
    
    <tabsheet name="TSTest">
    	<tab name="Test 1">Testing 1</tab>
    	<tab name="Test 2">Testing 2</tab>
    	<tab name="Test 3">Testing 3</tab>
    </tabsheet>
    
    
    <loop min="1" max="100">
    	<p><format type="pad" length="4"><count /></format></p>
    </loop>
    </div>
    (tabsheet was the main one, it generates the HTML from a TabSheet object I use which works like GUI style tabs using javascript to display the relevant pages; followed by <text> which i'm using to reference text in the language file. I added the others as PoC.)

    Then I set hooks up on the template like so:

    PHP Code:
    $template->addHook(new FormatHook('format'));
    $template->addHook(new TabSheetHook('tabsheet'));
    echo 
    $template->getOutput(); 
    The hook class looks like this. The run function gets passed an array of the attributes of the tag, e.g. <tag([attributes])>([content])</tag> along with the content from inside it.

    PHP Code:
    class FormatHook extends Hook {
        public function 
    run($attributes$content) {
            switch (
    $attributes['type']) {
                case 
    'floor': return floor($content);
                case 
    'ceil': return ceil($content);
                case 
    'round': return round($content$attributes['decimals']);        
            }
        }

    and the relevant parts of the template class. It uses Regex, I'm fairly sure parsing the entire template as a XML (after converting valid XHTML entities...), doing a getElementsByTagName for each node type, and then potentially parsing the output of the function and placing it back into the template with replaceChild() and finally printing the XML as text will be slower than a single regular expression which can capture them all.

    PHP Code:
    class Template {
    //....
    public function addHook(Hook $hook) {
            
    $this->hooks[$hook->tagName] = &$hook;
        }

    private function 
    runHook($matches) {
            
    $hook $this->hooks[$matches[1]];
            return (
    $hook instanceof SectionHook) ? $hook->run(self::getAttributes($matches[2]), $matches[4]) : $hook->run(self::getAttributes($matches[2]));
        }

        public function 
    getOutput() {
        
            if (
    count($this->hooks) > 0) {
                do 
    $this->output preg_replace_callback('/<(' implode('|'array_keys($this->hooks)) . ')([^>]*)(\/>|>(.*?)<\/\1>)/s', array($this'runHook'), $this->output); 
                while (
    preg_match('/<(' implode('|'array_keys($this->hooks)) . ')([^>]*)(\/>|>(.*?)<\/\1>)/s'$this->output));
            }
            return 
    $this->output;
        }


    the do/while is to capture nested tags correctly, but most of the time it's only ever going to do two preg_matches.

    This is an entirely regex solution but I am going to try a DOM version to test the speeds. I'm still not sure that it will be faster, but it's definately something I'm going to try.

    I will report back with my findings.

  10. #10
    SitePoint Guru
    Join Date
    Nov 2004
    Location
    England
    Posts
    702
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Thanks Tom


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •