Diazo frustration - converting global nav html structure - and solution

Just some rants on Diazo. When you think you've seen most of the necessary evil, the best is always yet to come.

Diazo processing order: Is there some logical reasoning behind the order in which the Diazo rules are processed? If I understood what the workflow / train of thought is to do theming with that order it might make some more sense. ( https://docs.plone.org/external/diazo/docs/basic.html#order-of-rule-execution )

Basic diazo theming has been reasonably simple to understand for me, but most examples stick to some conditions and when you cross a 'simple' border things get really complicated and error prone. One of those things is html structure: as soon as you need to modify html structure I'm always feeling like entering a mine field. There are quite a few example snippets online at different websites, but they all require using xsl: directives and then you're writing xslt which requires a lot of knowledge. So we still have to keep the theme html structure similar to the Pone constructs, which can get nasty if you forgot to tell that to your independent frontend contractor.

My 'simple' use case was to convert the plone portalnav li's to a list of divs. And it took me more than half a day. There are no obvious snippets and the ones that seemed similar didn't work for me (like http://docs.diazo.org/en/latest/recipes/create-list-from-anchors/index.html)

So first my current solution:

<!-- move global nav -->
<replace css:theme-children=".menu-nav-wrapper" css:if-content=".plone-navbar-nav">
    <xsl:for-each css:select=".plone-navbar-nav > li">
            <div><xsl:attribute name="class">
                  <xsl:when test="@class[contains(.,'selected')]">nav-tab active</xsl:when>
              </xsl:attribute><xsl:attribute name="id"><xsl:value-of select="@id"></xsl:value-of></xsl:attribute>
              <xsl:copy-of css:select="a"/>

It took me way too long to figure out an error message I had seen a few times before, but never really understood and at the time solved with a workaround: "runtime error, element 'attribute' [248:0] xsl:attribute: Cannot add attributes to an element if children have been already added to the element. [0:0]"

I was not adding any child tags/containers or other stuf. Wrong. This is a nasty little detail of XSLT: whitespace is significant and also part of your diazo rules.xml. I had a space between the <div> and the <xsl:attribute/> constructs or me or my editor had nicely put the <xsl:attribute's> on 2 separate lines. But this is also 'child node' and then you're no longer able to use <xsl:attributes/>.

From other examples I also see the direct use if <xsl:match/> and <xsl:apply-templates/> But when are these processed if you don't put them in a a diazo <replace></replace> construct? Are these always processed first before the Diazo replace rules go into effect? Another thing with using xsl:match is that I 'think' with using this approach you first modify the content in place with these directives and then 'in the end', copy the modified content over to the theme as long as you don't use method="raw. And you can process any node only once.

Diazo seems nice as long as you stay inside the fence, but you a) can't really see the fence and b) the nice green grass is outside of the designated 'diazo is easy area' even for some very simple tasks.

1 Like

To me, all the xls is black magic and will come for you one day…

If possible, I would make a new viewlet instead in such cases… it is reusable (?) and can be understood by mortals

Probably easier to add an override for the navigation as @espenmn proposed. These days I try to keep the Diazo rules to a minimum, and add extra view/viewlets where you need custom html. For older sites the complex Diazo rules can be very cumbersome (pita). With many rules the development environment also slows down significantly.