Generating html code, best practise?


(Rien) #1

I want to generate some HTML code with Swift. Of course there are many way to do this, but I am not looking to do an "in-dept all options open” approach.
Just some ‘get the html out quickly” type of thing.

So I wonder, how do _you_ do this?

Simply using Strings is one option, but cumbersome and without any ‘html-type-safety’
Using some general purpose function (e.g. func tagged(tag: String, content: String) -> String) helps a little, but not very much.
Enums are another possibility.
Or var’s in a struct/class that wrap the html element etc.

Many possibilities.

Any suggestion is welcome, suggestions as wel as experiences.
Of course if there is a solution out there, I’d like to know as well. (I didn’t find any though)

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl - A server for websites build in Swift


(^) #2

This problem isn’t all that different in Swift than it is in any other OO
language. As someone who has done a lot of this in the past, a good
strategy that worked is:

Create an “`HTMLNode`” superclass, and have inherited from it individual
tags such as `br`, `p`, `table`, `tr`, etc. In Swift it may be better to
use protocols and you can lower them to structs. Each tag struct should
have a few static properties indicating the tag’s ASCII name, whether or
not it’s allowed to contain text, and if you want, how the tag should be
indented. It should have two instance properties, a dictionary
`attributes:[String: String]`, and a contents vector. The vector is the
hardest thing to get right, since it contains all the children of the node,
which may include textual characters as well as node structs. If you are
not writing an editor, you may find it helpful to create a pseudotag struct
“text” that just contains a `String` so that your vector has a type
`HTMLNode` instead of `Any`. Alternatively you can use an `enum` with an
associated value to achieve a type-safe `Character`/`HTMLNode` union type.

You can easily build such a tree parsing an HTML file with two stacks.
Outputting the tree to a string is a little more complex if you want good
identation, but the main idea is you traverse the tree recursively, bumping
up the indentation level each time, and the emitter function can either
append a new String to the output vector, or append to the last String in
the output vector, depending on if the enclosing tag is allowed to contain
text, or if it can only contain other nodes.

To print the attributes inside the tags themselves, you want to use some
sort of “DNA” system to enforce type safety, and preserve canonical
ordering information, if desired.

Good luck!

···

On Fri, May 19, 2017 at 4:09 AM, Rien via swift-users <swift-users@swift.org > wrote:

I want to generate some HTML code with Swift. Of course there are many way
to do this, but I am not looking to do an "in-dept all options open”
approach.
Just some ‘get the html out quickly” type of thing.

So I wonder, how do _you_ do this?

Simply using Strings is one option, but cumbersome and without any
‘html-type-safety’
Using some general purpose function (e.g. func tagged(tag: String,
content: String) -> String) helps a little, but not very much.
Enums are another possibility.
Or var’s in a struct/class that wrap the html element etc.

Many possibilities.

Any suggestion is welcome, suggestions as wel as experiences.
Of course if there is a solution out there, I’d like to know as well. (I
didn’t find any though)

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl - A server for websites build in Swift

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rien) #3

Thanks Kelvin,

That pretty much sums it up.

It always a fight between verbosity and simplicity. Which is why I often end up using plain html instead. The gain from using a framework is just not big enough.
The reason for asking was just to check if somebody did find a particular efficient way or a particular elegant way of writing & outputting html from swift.
I have done some bike shedding, testing different approaches, but none seem to satisfy me. So for now, I’ll stick to plain html strings (again…)

As I was unaware of the support in NSAttributedString for HTML, that was a nice discovery (Thanks Erica!)

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl - A server for websites build in Swift

···

On 21 May 2017, at 22:05, Kelvin Ma <kelvin13ma@gmail.com> wrote:

This problem isn’t all that different in Swift than it is in any other OO language. As someone who has done a lot of this in the past, a good strategy that worked is:

Create an “`HTMLNode`” superclass, and have inherited from it individual tags such as `br`, `p`, `table`, `tr`, etc. In Swift it may be better to use protocols and you can lower them to structs. Each tag struct should have a few static properties indicating the tag’s ASCII name, whether or not it’s allowed to contain text, and if you want, how the tag should be indented. It should have two instance properties, a dictionary `attributes:[String: String]`, and a contents vector. The vector is the hardest thing to get right, since it contains all the children of the node, which may include textual characters as well as node structs. If you are not writing an editor, you may find it helpful to create a pseudotag struct “text” that just contains a `String` so that your vector has a type `HTMLNode` instead of `Any`. Alternatively you can use an `enum` with an associated value to achieve a type-safe `Character`/`HTMLNode` union type.

You can easily build such a tree parsing an HTML file with two stacks. Outputting the tree to a string is a little more complex if you want good identation, but the main idea is you traverse the tree recursively, bumping up the indentation level each time, and the emitter function can either append a new String to the output vector, or append to the last String in the output vector, depending on if the enclosing tag is allowed to contain text, or if it can only contain other nodes.

To print the attributes inside the tags themselves, you want to use some sort of “DNA” system to enforce type safety, and preserve canonical ordering information, if desired.

Good luck!

On Fri, May 19, 2017 at 4:09 AM, Rien via swift-users <swift-users@swift.org> wrote:
I want to generate some HTML code with Swift. Of course there are many way to do this, but I am not looking to do an "in-dept all options open” approach.
Just some ‘get the html out quickly” type of thing.

So I wonder, how do _you_ do this?

Simply using Strings is one option, but cumbersome and without any ‘html-type-safety’
Using some general purpose function (e.g. func tagged(tag: String, content: String) -> String) helps a little, but not very much.
Enums are another possibility.
Or var’s in a struct/class that wrap the html element etc.

Many possibilities.

Any suggestion is welcome, suggestions as wel as experiences.
Of course if there is a solution out there, I’d like to know as well. (I didn’t find any though)

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl - A server for websites build in Swift

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users