Diazo-rule to conditionally change the class of an element

I'm looking for a simple diazo-rule to change the class of an element depending on the existence of some other element.

<div class="foo">...</div>  
<div class="bar">...</div>

If .bar exists the css-class of .foo should change to 'baz'.

Something like this

 <rules css:if-content=".someclass">    
      <replace attributes="class" css:content=".bar">
           foo (not sure about syntax for this line

I don't think it can be done without xsl. Something like this might work:

<xsl:template match="//div[@class[contains(., 'foo')] and ../div[@class[contains(., 'bar')]]]">
        <xsl:attribute name="class">baz</xsl:attribute>
        <xsl:apply-templates />

With all the caveats, that this assumes div.foo and div.bar are siblings of the same parent, that there can be no classes like football or barbell, that div.foo has no other classes that you want to keep, etc.

Sadly none of the above solutions worked. What did work instead was conditionally copying the wanted class from another element:

<rules css:if-content=".bar">
    <copy attributes="class"
          css:content=".baz" />

The downside is that I now need to have a <div id="dummy" class="baz" /> somewhere in the content-html. But achieving this is easy and I can drop it anyway with <drop css:content="#dummy" />

Also: xslt is not for humans

1 Like
<replace content="//div[contains(@class,'foo')]/following-sibling::div[contains(@class,'bar')]/@class">
    <xsl:attribute name="class">baz</xsl:attribute>

I think this should be a solution.

Update: I forgot the @class at the end of the path


That looks legitimate.

@1letter did you try it? It does not seem to work.
Also: What if <div class="bar">...</div> is not a sibling but anywhere in the DOM?

then you should rewrite the rule :wink:

The following rule i use in my theme rules:

<!--  Transform Plone Cols to Bootstrap Grid -->
        <replace content="//div[contains(@class,'cell')]/@class">
            <xsl:attribute name="class">
                <xsl:if test='contains(current(),"width-3:4")'>col-xs-9 col-sm-9 col-md-9 col-lg-9</xsl:if>
                <xsl:if test='contains(current(),"width-2:3")'>col-xs-8 col-sm-8 col-md-8 col-lg-8</xsl:if>
                <xsl:if test='contains(current(),"width-1:2")'>col-xs-6 col-sm-6 col-md-6 col-lg-6</xsl:if>
                <xsl:if test='contains(current(),"width-1:3")'>col-xs-4 col-sm-4 col-md-4 col-lg-4</xsl:if>
                <xsl:if test='contains(current(),"width-1:4")'>col-xs-3 col-sm-3 col-md-3 col-lg-3</xsl:if>
                <xsl:if test='contains(current(),"width-full")'>col-xs-12 col-sm-12 col-md-12 col-lg-12</xsl:if>                
                <xsl:if test='contains(current(),"width-12")'>col-xs-12 col-sm-12 col-md-9 col-lg-9</xsl:if>
                <xsl:if test='contains(current(),"width-8")'>col-xs-12 col-sm-12 col-md-6 col-lg-6</xsl:if>
                <xsl:if test='contains(current(),"width-5")'>col-xs-12 col-sm-12 col-md-4 col-lg-4</xsl:if>
                <xsl:if test='contains(current(),"width-4")'>col-xs-12 col-sm-12 col-md-3 col-lg-3</xsl:if>

rule for anywhere in the dom:

//div[contains(@class,'foo') and //div[contains(@class,'bar')]]/@class
   <div class="foo">...</div>
   <div class="bar">...</div>
   <div class="bas">...</div>
   <div class="bad">...</div>
   <div class="bag">...</div>

check it online via this tool

Is this something that can be done more easily with css? .foo + bar { color: red;} the "+" is for adjacent sibling combinations

No, can't be done with css since he wants to change the class on the element before. You'd need a preceding sibling selector.

It looks like you are selecting the following sibling, i.e. .bar like that. I think it should be this:

<replace content="//div[contains(@class,'foo') and contains(following-sibling::div/@class,'bar')]/@class">
    <xsl:attribute name="class">baz</xsl:attribute>