Haml: Doctype doesn't affect format

Created on 24 May 2014  ·  11Comments  ·  Source: haml/haml

Source:

!!! xml
%wide310x150logo{src: 'mstile-310x150.png'}
%link{href: 'xyz.png'}

Expected:

<wide310x150logo src="mstile-310x150.png" />
<link href="xyz.png" />

Actual:

<wide310x150logo src="mstile-310x150.png"></wide310x150logo>
<link href="xyz.png">

With format: :xhtml the link tag gets the closing slash so it's valid, but I want HTML5 elsewhere; I shouldn't have to deal with that when the doctype is explicitly set to XML.

If the XML doctype always declared strict formatting that would fix this I think.

Feature Help Wanted

Most helpful comment

IMO, Haml template is responsible for what it renders, how it is compiled is a different layer and this feature request would make it hard to expect how the template will be compiled.

Hmm, I don’t really think it makes it hard to know how the template will be compiled: it will be compiled according to the global format option, unless an individual template specifically overrides it. This kind of settings cascade or local override is a well-understood mechanism in lots of computing contexts—I don’t think anyone would realistically be confused by it.

Right now, Haml can’t be used to solve certain common, real world problems because of this shortcoming.

Apart from that, actually we may not have the situation we want to specify format: :html and write xhtml doctype. And I think this feature request can be implemented. In this meaning, I agree with you.

Just to clarify, the problem is not that we want to generate HTML5 documents that contain an XHTML doctype. The problem is that we need certain templates to render in different formats entirely within the same project—e.g. some in HTML5 and some in XHTML. With the current behavior the only thing you can do is choose the doctype that gets output in a particular document, even though the markup being produced does not match that doctype because of the global format option.

But note that this is definitely backward-incompatible.

I’m not set on any particular solution to this problem—I would just like to be able to render templates in different formats within the same project. So if there’s a backwards-compatible way to achieve that functionality then I’m all for it.

Currently format option decides how doctype is rendered. With this feature, the decision direction will be reversed and we should not decide how doctype is rendered by format option, because format option itself is changed by doctype. It’s circular reference and definitely hacky.

It’s precisely this behavior that is leading to the confusion in the first place, I think. So you’re right that this change would be backwards compared to the current functionality—but I think the current behavior is backwards in the first place. If you look at the tickets I linked above, people are consistently confused by the existence of this format option and its interaction with the !!! doctype directive.

How do you distinguish !!! strict in format: :xhtml with !!! strict in format: :html? I think this idea can’t keep Haml’s behavior consistent.

To me, I think the ideal solution would be one where the !!! directive is not just outputting a doctype to the page but can also explicitly override the format option when necessary.

!!!: Generates a default doctype appropriate for the value of the format option.
!!! Strict: Generates a strict doctype appropriate for the value of the format option.
!!! Xhtml: Generates an XHTML doctype and explicitly overrides the format option for this template to :xhtml.
!!! Html5: Generates an HTML5 doctype and explicitly overrides the format option for this template to :html5.

I haven’t thought this through fully, though, and I’m not familiar with the Haml internals, and I agree that the above proposal would not be backwards-compatible. The above change would make it work the way I and many people expect it to work in the first place, though, and it would solve the particular problem of not being able to output documents in different formats in the same project. But again, I’m not married to a particular solution—I just would like some way to be able to change the format for individual templates, whatever the best solution for that might be.

All 11 comments

The single global format option is a huge pain in the neck. I’m constantly running into situations where I need HTML5 to be generated alongside other output formats in the same project.

For example, I have a Middleman website where the majority of the pages are HTML5 but where a subset of content needs to be XHTML 1.0 to have it served as an Apple Help book within a macOS desktop app. As a hack the site has to be built twice, twiddling the format option between runs with an environment variable, and then munging the content from the two separate builds together.

Similarly, in every recent Rails app I have worked on, the site itself needs to be HTML5 but emails need to be XHTML. I still haven’t found a good way to do this and simply resort to not using Haml for email templates, which is a shame.

I think the doctype directive should override the global format option allowing you to explicitly specify the doctype for a specific template. See #210 for an illustration of the confusion over this behavior dating way back to at least 2010. Right now the doctype directive violates the principal of least surprise and it makes it impossible to use Haml in examples such as the ones I gave above.

Take a look at #473, #195, and #203 for a few additional examples of people being confused and/or stymied by this behavior.

I have the same problem here. I need to render some of the templates in xhtml in order to generate pdf but the rest of the templates should be html5, otherwise it breaks my styles in some places.

For the pdf generation I use the render_to_string method. Is there any workaround to set the format to xhtml for just that case?

I tried the following options which didn't work:

  • Setting !!! Strict in the layout (which does not work when format is set to html5)
  • passing the option format: :xhtml to the render_to_string method
  • passing formats: Mime::XML to the render_to_string

None of these did work. The only way for the moment is to use something like this in the templates:

= '<br />'.html_safe

for all the empty tags that need closing. This is definitely not the way to go but is currently the only workaround I've found unless I switch to erb...

Changing compile format inside template is a little hacky.

This is just idea: How about allowing to switch format by filename like foo.xhtml.haml or bar.xml.haml? Interface of Haml may have some possibilities.

None of these did work. The only way for the moment is to use something like this in the templates:
= '<br />'.html_safe

Off topic: I think you can write it as (of course we should consider the solution I commented above):

<br />

@k0kubun I guess it’s a matter of perspective, but I don’t see anything hacky about specifying the format inside the template—what better place to indicate the format that a template is compiled using than in the template itself? This is already basically what the doctype in an HTML document is doing in the first place.

From the point of view of pragmatism I wouldn’t have a problem with the filename determining the format, except that doesn’t work in situations where you need a file to be generated in XHTML but with an .html extension—such as the case with Apple Help books.

but I don’t see anything hacky about specifying the format inside the template

IMO, Haml template is responsible for what it renders, how it is compiled is a different layer and this feature request would make it hard to expect how the template will be compiled.


Apart from that, actually we may not have the situation we want to specify format: :html and write xhtml doctype. And I think this feature request can be implemented. In this meaning, I agree with you.

But note that this is definitely backward-incompatible. Hardly introduced if it's not discussed well. And I have a following concern:

Currently format option decides how doctype is rendered. With this feature, the decision direction will be reversed and we should not decide how doctype is rendered by format option, because format option itself is changed by doctype. It's circular reference and definitely hacky. How do you distinguish !!! strict in format: :xhtml with !!! strict in format: :html? I think this idea can't keep Haml's behavior consistent.

IMO, Haml template is responsible for what it renders, how it is compiled is a different layer and this feature request would make it hard to expect how the template will be compiled.

Hmm, I don’t really think it makes it hard to know how the template will be compiled: it will be compiled according to the global format option, unless an individual template specifically overrides it. This kind of settings cascade or local override is a well-understood mechanism in lots of computing contexts—I don’t think anyone would realistically be confused by it.

Right now, Haml can’t be used to solve certain common, real world problems because of this shortcoming.

Apart from that, actually we may not have the situation we want to specify format: :html and write xhtml doctype. And I think this feature request can be implemented. In this meaning, I agree with you.

Just to clarify, the problem is not that we want to generate HTML5 documents that contain an XHTML doctype. The problem is that we need certain templates to render in different formats entirely within the same project—e.g. some in HTML5 and some in XHTML. With the current behavior the only thing you can do is choose the doctype that gets output in a particular document, even though the markup being produced does not match that doctype because of the global format option.

But note that this is definitely backward-incompatible.

I’m not set on any particular solution to this problem—I would just like to be able to render templates in different formats within the same project. So if there’s a backwards-compatible way to achieve that functionality then I’m all for it.

Currently format option decides how doctype is rendered. With this feature, the decision direction will be reversed and we should not decide how doctype is rendered by format option, because format option itself is changed by doctype. It’s circular reference and definitely hacky.

It’s precisely this behavior that is leading to the confusion in the first place, I think. So you’re right that this change would be backwards compared to the current functionality—but I think the current behavior is backwards in the first place. If you look at the tickets I linked above, people are consistently confused by the existence of this format option and its interaction with the !!! doctype directive.

How do you distinguish !!! strict in format: :xhtml with !!! strict in format: :html? I think this idea can’t keep Haml’s behavior consistent.

To me, I think the ideal solution would be one where the !!! directive is not just outputting a doctype to the page but can also explicitly override the format option when necessary.

!!!: Generates a default doctype appropriate for the value of the format option.
!!! Strict: Generates a strict doctype appropriate for the value of the format option.
!!! Xhtml: Generates an XHTML doctype and explicitly overrides the format option for this template to :xhtml.
!!! Html5: Generates an HTML5 doctype and explicitly overrides the format option for this template to :html5.

I haven’t thought this through fully, though, and I’m not familiar with the Haml internals, and I agree that the above proposal would not be backwards-compatible. The above change would make it work the way I and many people expect it to work in the first place, though, and it would solve the particular problem of not being able to output documents in different formats in the same project. But again, I’m not married to a particular solution—I just would like some way to be able to change the format for individual templates, whatever the best solution for that might be.

Thank you for your opinion. I'm open to hear other ideas to find the best solution for this. This is a little difficult problem.

Yes, thanks for discussing it! This is just my perspective as a Haml user—I understand this is a tricky problem to fix and there probably isn’t a good solution that would work for everyone. I do definitely see your point that overriding the format in the templates themselves is hacky certainly from the way Haml currently works, and that having the !!! directive do two things at once (output a doctype and potentially change the format setting) is problematic and inconsistent in its own way. The problem is to work around the current behavior in a project that uses Haml requires some really big and ugly hacks of their own.

This is definitely interesting. Especially considering changing fashions. When Haml was a new baby OSS project– doctypes were all the rage, but by the time we got around to 2010, we started moving away from them. And at this point, so many people are writing SPAs that I bet half the junior developers I work with aren't even sure what a doctype is.

I do feel that as we are a project that specifically supports HTML (and XHTML)– that the doctype should be the primary driver of the output. That makes sense to me and would be my natural assumption.

Now, of course, as soon as we do that– we'll have people say "But I WANT my XML document to be HTML5-like!"– except I think we can all agree they'd be wrong. It's much more pleasant to say "Ah, yes, this is an XML file... and here I am declaring it clearly!" and that we then trust that.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

djrodgerspryor picture djrodgerspryor  ·  3Comments

yb66 picture yb66  ·  4Comments

Shamaoke picture Shamaoke  ·  14Comments

tisba picture tisba  ·  10Comments

k0kubun picture k0kubun  ·  13Comments