Recent Posts

Showing posts with label XHTML. Show all posts
Showing posts with label XHTML. Show all posts

Matching HTML Opening Tags with Regex while Excluding Self-Closing XHTML Tags

 I need to match all of these opening tags:


<p>
<a href="foo">
 

But not self-closing tags:


<br />
<hr class="foo" />
 
 

HTML is a non-regular language, meaning its nested and recursive structure cannot be reliably parsed using Regular Expressions (Regex). Regex is designed for regular languages and lacks the memory and logic required to handle the complexities of HTML tag balancing, attributes, and comments. Attempting to use Regex for this task leads to brittle code, significant security vulnerabilities, and logic that fails on edge cases. Always use a dedicated DOM parser library instead.

I know it’s tempting to grab a Regex for a quick HTML fix, but trust me: don't do it. HTML is way too complex for Regex to understand. Even 'advanced' expressions can't handle the way HTML tags nest inside each other. If you try, you’ll end up with a mess of 'spaghetti code' that breaks the moment the input changes slightly. Save yourself the headache and use a tool built for the job, like a proper HTML parser.

Trying to parse HTML with Regex is the fastest way to lose your mind. You aren't just writing a bad pattern; you're inviting chaos into your codebase. HTML is a recursive labyrinth that Regex wasn't built to navigate. Every time you try to 'hack' a solution with a regular expression, a bug is born that will eventually crash your app and ruin your weekend. For the sake of your sanity and your security, put down the Regex and pick up a DOM library. The abyss is real, and it doesn't want your code.

Including another XHTML in XHTML using JSF 2.0 Facelets

Most basic way is <ui:include>. The included content must be placed inside <ui:composition>.

Kickoff example of the master page /page.xhtml:

<!DOCTYPE html>
<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:head>
        <title>Include demo</title>
    </h:head>
    <h:body>
        <h1>Master page</h1>
        <p>Master page blah blah lorem ipsum</p>
        <ui:include src="/WEB-INF/include.xhtml" />
    </h:body>
</html>
The include page /WEB-INF/include.xhtml:

<ui:composition 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
    <h2>Include page</h2>
    <p>Include page blah blah lorem ipsum</p>
</ui:composition>
This needs to be opened by /page.xhtml.

A more advanced way of including is templating. This includes basically the other way round. The master template page should use <ui:insert> to declare places to insert defined template content. The template client page which is using the master template page should use <ui:define> to define the template content which is to be inserted.

Master template page /WEB-INF/template.xhtml:

<!DOCTYPE html>
<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:head>
        <title><ui:insert name="title">Default title</ui:insert></title>
    </h:head>
    <h:body>
        <div id="header">Header</div>
        <div id="menu">Menu</div>
        <div id="content"><ui:insert name="content">Default content</ui:insert></div>
        <div id="footer">Footer</div>
    </h:body>
</html>
(the header, menu and footer can in turn even be <ui:include> files)

Template client page /page.xhtml (note the template attribute):

<ui:composition template="/WEB-INF/template.xhtml"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

    <ui:define name="title">
        New page title here
    </ui:define>

    <ui:define name="content">
        <h1>New content here</h1>
        <p>Blah blah</p>
    </ui:define>
</ui:composition>
This needs to be opened by /page.xhtml. If there is no <ui:define>, then the default content inside <ui:insert> will be displayed instead, if any.

Note that the files which aren't supposed to be publicly accessible by just entering/guessing its URL are been placed in /WEB-INF folder, like as the include file and the template file. See also Which XHTML files do I need to put in /WEB-INF and which not?

Also note that there isn't any markup outside <ui:composition> nor <ui:define>. You can put any, but they will be ignored by Facelets. Putting markup in there is only useful for web designers. See also Is there a way to run a JSF page without building the whole project?

For a live example of advanced Facelets templating, check the WebContent folder of OmniFaces showcase site source code.