Uploaded image for project: 'Forrest'
  1. Forrest
  2. FOR-1167

class attribute of body element in XDocs source is not included in generated HTML

    Details

      Description

      Here is the body element of my XDocs source file:

      <body class="product_heading">

      The generated HTML does not include the class attribute.

      See <http://thread.gmane.org/gmane.text.xml.forrest.devel/27106>.
      1. FOR-1167-skins.patch
        3 kB
        Sina K. Heshmati

        Activity

        Hide
        sindoc Sina K. Heshmati added a comment -
        I was able to locate [1] where <body> of final HTML documents is generated; but only for skin-based websites.

        As for websites based on the dispatcher, my early guess is that <body> is not generated by XSLT stylesheets. That said, I'm sure others can provide a more definite answer.

        [1] $FORREST_HOME/main/webapp/skins/pelt/xslt/html/site-to-xhtml.xsl
        Show
        sindoc Sina K. Heshmati added a comment - I was able to locate [1] where <body> of final HTML documents is generated; but only for skin-based websites. As for websites based on the dispatcher, my early guess is that <body> is not generated by XSLT stylesheets. That said, I'm sure others can provide a more definite answer. [1] $FORREST_HOME/main/webapp/skins/pelt/xslt/html/site-to-xhtml.xsl
        Hide
        ipv6guru Gavin added a comment -
        Thanks Sina,

        I think in this case, as the <body> referred to comes from a content xml document, it should be transformed using the document-to-html.xsl stylesheets.
        If you look in both skins and dispatcher, for common and pelt skins/themes, you will see this file in each case.

        In each of files is the line

        <xsl:template match="body">

        So, what needs to happen something like


        <xsl:template match="body">
              <xsl:if test="@class">
                <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>
              </xsl:if>

        Anyone fancy testing that out and having a go at the patch ?

        Just try it on a 'forrest seed' site first using the common version of document-to-html.xsl should be enough to test, if it works, try it out on the others.
        Show
        ipv6guru Gavin added a comment - Thanks Sina, I think in this case, as the <body> referred to comes from a content xml document, it should be transformed using the document-to-html.xsl stylesheets. If you look in both skins and dispatcher, for common and pelt skins/themes, you will see this file in each case. In each of files is the line <xsl:template match="body"> So, what needs to happen something like <xsl:template match="body">       <xsl:if test="@class">         <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute>       </xsl:if> Anyone fancy testing that out and having a go at the patch ? Just try it on a 'forrest seed' site first using the common version of document-to-html.xsl should be enough to test, if it works, try it out on the others.
        Hide
        sindoc Sina K. Heshmati added a comment -
        Gavin,

        I was also under the same impression when I first attempted to resolve this issue, but I realized at some point that an XDoc <body> is not equivalent to the <body> in the final HTML output; although it could correspond to e.g. <div id="main-content">. My definition of equivalence here is the fact that none of the inspected stylesheets handles an XDoc <body> as follows, which means that the <body> in the final output does not depend on the XDoc <body>.

        <xsl:template match="body">
          <body>
            ...
          </body>
        </xsl:template>

        That said, we could establish this equivalence relation between the two body elements but this is not the case right now as e.g. sidebar or header elements might be processed prior to the actual content of a page.

        Now, here's a sequence of steps that might help resolve the issue:

        <html:body> = <body> in final HTML pages
        <xdoc:body> = Semantic <body> in XDocs source files

        (S1) Find out *where* <html:body> is being generated.
        (S2) Access <xdoc:body> from the context found in (S1).
        (S3) Copy attributes of <xdoc:body> to <html:body>

        Progress so far:
        Dispatcher-based: Stuck in (S1)
        Skin-based: Stuck in (S2)

        In order to access <xdoc:body> from site-to-xhtml.xsl where <html:body> is generated, I need to know what the input to site-to-xhtml.xsl looks like. If the input is site.xml as it is written by the user, then we could use xpath to access <xdoc:body>. Once (S2) is complete, the issue for skin-based sites is almost resolved given that (S3) is rather trivial.
        Show
        sindoc Sina K. Heshmati added a comment - Gavin, I was also under the same impression when I first attempted to resolve this issue, but I realized at some point that an XDoc <body> is not equivalent to the <body> in the final HTML output; although it could correspond to e.g. <div id="main-content">. My definition of equivalence here is the fact that none of the inspected stylesheets handles an XDoc <body> as follows, which means that the <body> in the final output does not depend on the XDoc <body>. <xsl:template match="body">   <body>     ...   </body> </xsl:template> That said, we could establish this equivalence relation between the two body elements but this is not the case right now as e.g. sidebar or header elements might be processed prior to the actual content of a page. Now, here's a sequence of steps that might help resolve the issue: <html:body> = <body> in final HTML pages <xdoc:body> = Semantic <body> in XDocs source files (S1) Find out *where* <html:body> is being generated. (S2) Access <xdoc:body> from the context found in (S1). (S3) Copy attributes of <xdoc:body> to <html:body> Progress so far: Dispatcher-based: Stuck in (S1) Skin-based: Stuck in (S2) In order to access <xdoc:body> from site-to-xhtml.xsl where <html:body> is generated, I need to know what the input to site-to-xhtml.xsl looks like. If the input is site.xml as it is written by the user, then we could use xpath to access <xdoc:body>. Once (S2) is complete, the issue for skin-based sites is almost resolved given that (S3) is rather trivial.
        Hide
        brolin Brolin Empey added a comment -
        Has any more progress been made?  I have to use “forrest.sh build” for
        one of my Web sites until this issue is solved because forrest.sh's
        post-build function runs sed to hack the generated HTML to add a class
        attribute to the <body> of one page.
        Show
        brolin Brolin Empey added a comment - Has any more progress been made?  I have to use “forrest.sh build” for one of my Web sites until this issue is solved because forrest.sh's post-build function runs sed to hack the generated HTML to add a class attribute to the <body> of one page.
        Hide
        sindoc Sina K. Heshmati added a comment -
        This patch helps transfer the class attribute from <xdoc:body> to <html:body> for Pelt skin. The transfer is intentionally limited to @class but it's quite simple to extend the stylesheets to convey more attributes.

        Let's say we'd also like to have @onunload transfered, then we'd have to add two templates to two stylesheets as follows:

        (Step. 1.1) to $FORREST_HOME/main/webapp/skins/common/xslt/html/document-to-html.xsl

        This will help copy @onunload from <xdoc:body> to <div id="content"/> that is part of the document processed by site-to-xhtml.xsl --where <html:body> is generated. This is not an ideal choice but adding an extra element might have broken other templates.

        <xsl:template match="@onunload" mode="carry-body-attribs">
          <xsl:attribute name="onunload">
            <xsl:value-of select="."/>
           </xsl:attribute>
         </xsl:template>

        (Step. 1.2) to $FORREST_HOME/main/webapp/skins/common/xslt/html/site-to-xhtml.xsl

        Now, attributes are copied from <div id="content"/> to <html:body>.

          <xsl:template match="@onunload" mode="carry-body-attribs">
            <xsl:attribute name="onunload">
              <xsl:value-of select="."/>
            </xsl:attribute>
          </xsl:template>

        Even though the two templates look exactly alike but they do different things. Adding i.e. @onload might be more complicated as <html:body> already has an @onload; so carrying attributes that already exist will require special care.

        Fixing this issue for other skins would be as simple as adding two instructions to document-to-html.xsl and site-to-xhtml.xsl of each skin.

        (Step 2.1) to $FORREST_HOME/main/webapp/skins/${SKIN-NAME}/xslt/html/document-to-html.xsl
        <xsl:apply-templates select="body" mode="carry-body-attribs"/>
        After <div id="content"> in <xsl:template match="document"/>

        (Step 2.2) to $FORREST_HOME/main/webapp/skins/${SKIN-NAME}/xslt/html/site-to-xhtml.xsl
        After <body .../> in <xsl:template match="site"/>
        <xsl:call-template name="carry-body-attribs"/>
        Show
        sindoc Sina K. Heshmati added a comment - This patch helps transfer the class attribute from <xdoc:body> to <html:body> for Pelt skin. The transfer is intentionally limited to @class but it's quite simple to extend the stylesheets to convey more attributes. Let's say we'd also like to have @onunload transfered, then we'd have to add two templates to two stylesheets as follows: (Step. 1.1) to $FORREST_HOME/main/webapp/skins/common/xslt/html/document-to-html.xsl This will help copy @onunload from <xdoc:body> to <div id="content"/> that is part of the document processed by site-to-xhtml.xsl --where <html:body> is generated. This is not an ideal choice but adding an extra element might have broken other templates. <xsl:template match="@onunload" mode="carry-body-attribs">   <xsl:attribute name="onunload">     <xsl:value-of select="."/>    </xsl:attribute>  </xsl:template> (Step. 1.2) to $FORREST_HOME/main/webapp/skins/common/xslt/html/site-to-xhtml.xsl Now, attributes are copied from <div id="content"/> to <html:body>.   <xsl:template match="@onunload" mode="carry-body-attribs">     <xsl:attribute name="onunload">       <xsl:value-of select="."/>     </xsl:attribute>   </xsl:template> Even though the two templates look exactly alike but they do different things. Adding i.e. @onload might be more complicated as <html:body> already has an @onload; so carrying attributes that already exist will require special care. Fixing this issue for other skins would be as simple as adding two instructions to document-to-html.xsl and site-to-xhtml.xsl of each skin. (Step 2.1) to $FORREST_HOME/main/webapp/skins/${SKIN-NAME}/xslt/html/document-to-html.xsl <xsl:apply-templates select="body" mode="carry-body-attribs"/> After <div id="content"> in <xsl:template match="document"/> (Step 2.2) to $FORREST_HOME/main/webapp/skins/${SKIN-NAME}/xslt/html/site-to-xhtml.xsl After <body .../> in <xsl:template match="site"/> <xsl:call-template name="carry-body-attribs"/>
        Hide
        brolin Brolin Empey added a comment -
        Thanks Sina! Your patch appears to work. :)
        Show
        brolin Brolin Empey added a comment - Thanks Sina! Your patch appears to work. :)
        Hide
        ipv6guru Gavin added a comment -
        Thanks Sina, tested and works fine, applied to trunk.

        I'll leave this issue open until a Dispatcher version works.
        Show
        ipv6guru Gavin added a comment - Thanks Sina, tested and works fine, applied to trunk. I'll leave this issue open until a Dispatcher version works.
        Hide
        ipv6guru Gavin added a comment -
        Equivalent files for dispatcher are in:

        $FORREST\whiteboard\plugins\org.apache.forrest.plugin.internal.dispatcher\resources\stylesheets\html\

        document-to-html.xsl and xhtml2_to_html.xsl
        Show
        ipv6guru Gavin added a comment - Equivalent files for dispatcher are in: $FORREST\whiteboard\plugins\org.apache.forrest.plugin.internal.dispatcher\resources\stylesheets\html\ document-to-html.xsl and xhtml2_to_html.xsl
        Hide
        sindoc Sina K. Heshmati added a comment -
        @class is properly handled in xhtml2_to_html.xsl. Now, the questions is whether this stylesheet is used somewhere in the process of generating the final output. There's a pipeline that transforms XDoc into XHTML2 (i.e. internal.**.*) but no other pipeline seems to be calling it.

        document-to-html.xsl still helps us copy <html:body> attributes to e.g. <div id="content"> making them available in **.body.xml, which we could pass as data to a contract as follows:

        <forrest:contract name="convey-body-class-attrib" dataURI="cocoon://#{$getRequest}.body.xml"/>

        Here's the contract itself:

          <forrest:template xmlns:forrest="http://apache.org/forrest/templates/1.0"
            name="convey-body-class-attrib" inputFormat="xsl">
            <xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
              <xsl:template match="/">
                <forrest:content>
                  <forrest:part xpath="/html/body">
                    <xsl:apply-templates select="//div[@id='content']/@*" mode="carry-body-attribs"/>
                  </forrest:part>
                </forrest:content>
              </xsl:template>
              <xsl:template match="@id" mode="carry-body-attribs">
                <!-- Ignore @id -->
              </xsl:template>
              <xsl:template match="@class" mode="carry-body-attribs">
                <xsl:attribute name="class">
                  <xsl:value-of select="."/>
                </xsl:attribute>
              </xsl:template>
            </xsl:stylesheet>
          </forrest:template>

        The above contract tries to insert @class but *to which node* (?) We can be sure that this contract is called right after the body element by calling it right after /html/head contracts but it still doesn't add the attribute to the <body>. This is consistent with my earlier guess suggesting that <body> is not generated by XSLT stylesheets.

        <html:body> is generated by org.apache.forrest.dispatcher.transformation.DispatcherTransformer.

        private void contractProcessingEnd() throws SAXException {
        ...
          else {
            xpathNode = createXpathNode(location);
            appendChildToResultIterator(root, finalContent, xpathNode);
          }
         ...
        }

        The above solution didn't work because we were trying to add *just an attribute* to a node. It would have worked if we had to add an element. So one possible fix is to hack DispatcherTransformer.java so that nodes that only consist of attributes are also added to the result document.

        A more elegant solution is to make good use of @xpath e.g.:

        <forrest:part xpath="/html/body/@class">
          <xsl:apply-templates select="//div[@id='content']/@*" mode="carry-body-attribs"/>
        </forrest:part>
        ...
        <xsl:template match="@class" mode="carry-body-attribs">
          <xsl:value-of select="."/>
        </xsl:template>

        This won't work either because @xpath is limited to simple expressions such as /html/body and does not support more complex XPath expressions. This issue has already been discussed [1] with Thorsten. I think this is a feature worth implementing.

        So the idea is for a contract to choose where to add the content it generates. The target node is selected using @xpath and it shouldn't matter how complex the XPath expression is as long as the move is valid and there are no conflicts between nodes.

        [1] http://markmail.org/message/zgispeyrmmwfej3e
        Show
        sindoc Sina K. Heshmati added a comment - @class is properly handled in xhtml2_to_html.xsl. Now, the questions is whether this stylesheet is used somewhere in the process of generating the final output. There's a pipeline that transforms XDoc into XHTML2 (i.e. internal.**.*) but no other pipeline seems to be calling it. document-to-html.xsl still helps us copy <html:body> attributes to e.g. <div id="content"> making them available in **.body.xml, which we could pass as data to a contract as follows: <forrest:contract name="convey-body-class-attrib" dataURI=" cocoon://# {$getRequest}.body.xml"/> Here's the contract itself:   <forrest:template xmlns:forrest=" http://apache.org/forrest/templates/1.0 "     name="convey-body-class-attrib" inputFormat="xsl">     <xsl:stylesheet version="1.1" xmlns:xsl=" http://www.w3.org/1999/XSL/Transform ">       <xsl:template match="/">         <forrest:content>           <forrest:part xpath="/html/body">             <xsl:apply-templates select="//div[@id='content']/@*" mode="carry-body-attribs"/>           </forrest:part>         </forrest:content>       </xsl:template>       <xsl:template match="@id" mode="carry-body-attribs">         <!-- Ignore @id -->       </xsl:template>       <xsl:template match="@class" mode="carry-body-attribs">         <xsl:attribute name="class">           <xsl:value-of select="."/>         </xsl:attribute>       </xsl:template>     </xsl:stylesheet>   </forrest:template> The above contract tries to insert @class but *to which node* (?) We can be sure that this contract is called right after the body element by calling it right after /html/head contracts but it still doesn't add the attribute to the <body>. This is consistent with my earlier guess suggesting that <body> is not generated by XSLT stylesheets. <html:body> is generated by org.apache.forrest.dispatcher.transformation.DispatcherTransformer. private void contractProcessingEnd() throws SAXException { ...   else {     xpathNode = createXpathNode(location);     appendChildToResultIterator(root, finalContent, xpathNode);   }  ... } The above solution didn't work because we were trying to add *just an attribute* to a node. It would have worked if we had to add an element. So one possible fix is to hack DispatcherTransformer.java so that nodes that only consist of attributes are also added to the result document. A more elegant solution is to make good use of @xpath e.g.: <forrest:part xpath="/html/body/@class">   <xsl:apply-templates select="//div[@id='content']/@*" mode="carry-body-attribs"/> </forrest:part> ... <xsl:template match="@class" mode="carry-body-attribs">   <xsl:value-of select="."/> </xsl:template> This won't work either because @xpath is limited to simple expressions such as /html/body and does not support more complex XPath expressions. This issue has already been discussed [1] with Thorsten. I think this is a feature worth implementing. So the idea is for a contract to choose where to add the content it generates. The target node is selected using @xpath and it shouldn't matter how complex the XPath expression is as long as the move is valid and there are no conflicts between nodes. [1] http://markmail.org/message/zgispeyrmmwfej3e
        Hide
        williamstw Tim Williams added a comment -
        With the last patch, this issue seems only to apply to dispatcher, so I've removed the 'skins' part of the component, and moving to .10.
        Show
        williamstw Tim Williams added a comment - With the last patch, this issue seems only to apply to dispatcher, so I've removed the 'skins' part of the component, and moving to .10.
        Hide
        brolin Brolin Empey added a comment -
        This bug appears to still exist for HTML source files too. :( Can anyone fix it? I need to use an HTML source file for a Contact form Web page because only HTML source files can contain HTML form elements.
        Show
        brolin Brolin Empey added a comment - This bug appears to still exist for HTML source files too. :( Can anyone fix it? I need to use an HTML source file for a Contact form Web page because only HTML source files can contain HTML form elements.

          People

          • Assignee:
            Unassigned
            Reporter:
            brolin Brolin Empey
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:

              Development