I am currently swamped with work but I am certainly coming back to this when I get a chance. Just to reinforce the point that sometimes you want to generate XML and not just HTML, here is another use case of very similar API: [link:bitbucket.org] - this is used to generate MSBuild and other XML files to automate some aspects of building software.

By on 3/18/2013 2:37 PM ()

[Cross-posting from the fsharp-opensource mailing list]

Hi,
The idea of having a standard DSL for creating HTML in F# sounds great! If we had a wide agreement and it came with Apache license, I think it would be great to support that in FunScript too (and in various server-side frameworks).

Some time ago, I wrote a DSL - it was never quite complete, but here is how it looked: [link:fssnip.net]

Here are some desing guidelines that I tried to follow:

  • Make it type-safe (use "." to get IntelliSense - the types could be generated by a type provider - and it could be made extensible by allowing "?" in place of dot).
  • Use as few custom operators as possible (I still needed one - % for embedding strings in the HTML, but for example, attributes were set using the standard F# syntax "foo(attr1=value1, ...)")
  • Avoid noise like "yield" and "box" when writing a template that is generated from a list of values

I think getting the third when using list comprehensions might be tricky, but having an occasional "yield" is probably quite fine. But I think the first two are quite important - I think element names & attributes should be (in most cases) statically checked and it should avoid too many custom operators.

Another project that is worth checking out is: [link:wingbeats.codeplex.com]

By on 3/12/2013 7:11 AM ()

Hi Tomas,

Your DSL is one of the most creative ones I seen :) It definitely
looks very nice.

But to me composing elements with side effects seems like a big price
to pay. I imagine it does not play very well with `let-` binding
intermediate results, and the need for a global page object is a bit
of a concern. I think that if at all viable, I would prefer explicit
composition of values over using side effects, even if it means a
little longer syntax, just to make it easier for programmers to
understand the meaning of what they write and make sure the
transformations they do are safe.

About your three points - I agree.

1. Absolutely - I envision say a baseline FSharp.Markup.dll combined
with specific FSharp.Markup.Html5 and FSharp.Markup.Xml; then say in
FSharp.Markup.Html5 we can define the entire HTML5 vocabulary for
elements and attributes, maybe even parsed out of the standard. Just
need to make sure that while we are providing these members we still
make it easy to define new attributes and elements in user code. For
example, HTML5 allows data-* extension attributes, and XML obviously
allows arbitrary user vocabulary.

2. Custom attributes are indeed very arbitrary, and it would be nice
to avoid them entirely. However, in my attempts to avoid them, I have
not yet got the result to be concise enough to my taste - see the
problem with #3. So I would always be tempted to define some operators
as a user of the library. In the end I think it can be an OK
compromise to use some operators provided that : (a) it is NOT
necessary to use them - there are equivalent named members for all
functionality; (b) they do not pollute your global scope unless you
very explicitly say so (open FSharp.Markup.Operators). Then operators
are simply a convenience.

3. Indeed. Here are a few basic choices. Are attributes treated the
same as content nodes or separately? Is box/upcast necessary when
content nodes are mixed (text/element) nodes? When they are
homogeneous (text or element)?

I am inclined to treat attributes separately and provide specific
methods (and, if desired for convenience, operators) for special cases
that come up when writing HTML/XML. Some frequent cases to consider:

<hr /> -- empty element with no attributes
<link rel="stylesheet" href="foo.css" /> -- empty element with attributes
<title>foo</title> -- empty element with text-only content
<div id="main">foo</div> -- empty element with attributes and text-only content
<div><hr/></div> -- element with no attributes and element-only content
<div id="main"><hr/></div> -- element with attributes and element-only content
<div id="address">Foo St
Bar Town</div> -- element (possibly with
attributes) with mixed content

With the [link:gist.github.com] syntax, here is how
it would look (provided a suitable HTML vocabulary in scope):

hr
link -@ [rel "stylesheet"; href "foo.css"]
title -% "foo"
div -@ [id "main"] -% "foo"
div -^ [hr]
div -@ [id "main"] -^ [hr]
div -@ [id "address"] -* [text "Foo St"; br; text "Bar Town"]

-* ~ WithMixedChildren
-^ ~ WithChildren
-@ ~ WithAttributes
-% ~ WithText

Spelling out the operators is annoying, and eliding them would be very
nice. But that needs some clever use of overloading that I guess I
just don't see yet.

I'll need to have a closer look at both wingbeats and fmarkup when I
have some time. Might be some great ideas there that I'm missing.

Thanks,

--A

By on 3/12/2013 8:17 AM ()

Hi Anton,
My 'teach my self F#' project from some time ago used exactly this structure: several auto-opening modules for the core functionality of building generic 'tag' structures, and then sub modules (that could be in separate dlls) for html specific helpers and 'punctuation' (as I called my custom operators module).

It's underlying code is not the way I'd write it now, but the structure and functionality are useful enough that I've used the library several times in my own mini projects. It's at [link:github.com] .

Michael

By on 3/16/2013 4:02 AM ()

Thanks. Any thoughts on how you would write it now? :)

By on 3/18/2013 2:35 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper