10 Replies Latest reply on Jul 8, 2009 5:12 PM by Vladimir Guerra Miller

    How to display an XML file transformed by XSL SS file with seam?

    Vladimir Guerra Miller Newbie

      I tried to display an XML file after transform it with an xsl file, but it doesn´t work. I tried to use richfaces components into the xsl file to do that, but I got not result.

        • 1. Re: How to display an XML file transformed by XSL SS file with seam?
          Nikos Paraskevopoulos Novice

          What exactly are you trying to do?


          Simply display a XML after transforming it (eg to HTML) or use the transformed XML as a Facelet and display that as a JSF view? Or something else?


          You cannot use JSF components in the first case. The transformed XML will not pass through the JSF mechanism at all. The second case can be done, but is tricky for the beginner.

          • 2. Re: How to display an XML file transformed by XSL SS file with seam?
            Vladimir Guerra Miller Newbie
            I want to display an XML file but I´m doing a mach between the XML and xsl styleSheet which could be use for several xml files looking for friendly interfaces with richfaces components, I thought that it will work including richfaces component in the xsl file but it doesn´t.Look like it never pass through the JSF mechanism.

            If you could help me, I´ll be so grateful. I´m a beginner, but I must do that, not matter how tricky it can be.

            This is an example of my proof files:

            XML:

            <?xml version="1.0" encoding='ISO-8859-1'?>
            <?xml-stylesheet href="tienda1.xsl" type="text/xsl"?>
            <mercado>
                 <tienda>
                      <nombre>
                           La tiendecilla
                      </nombre>
                      
                      <telefono>
                           953 87 12 23
                      </telefono>
                      
                      <producto>
                           <codigo>
                                92
                           </codigo>
                           
                           <cantidad>
                                10
                           </cantidad>
                           
                           <articulo>
                                Radio-Casette
                           </articulo>
                      </producto>
                      
                      <producto>
                           <codigo>
                                103
                           </codigo>
                           
                           <cantidad>
                                50
                           </cantidad>
                           
                           <articulo>
                                Reloj Cocina
                           </articulo>
                      </producto>
                      
                      <producto>
                           <codigo>
                                1312
                           </codigo>
                           
                           <cantidad>
                                3
                           </cantidad>
                           
                           <articulo>
                                Sofá
                           </articulo>
                      </producto>
                 </tienda>
            </mercado>

            XSL:

            <?xml version="1.0" encoding="UTF-8"?>
            <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     
                 <xsl:template match='/'>
                      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                      <xsl:element name="ui:composition">
                           <xsl:attribute name="xmlns">
                                <xsl:text>http://www.w3.org/1999/xhtml</xsl:text>
                           </xsl:attribute>                 
                            <xsl:attribute name="xmlns:ui">
                                 <xsl:text>http://java.sun.com/jsf/facelets</xsl:text>
                            </xsl:attribute>
                          <xsl:attribute name="xmlns:h">
                               <xsl:text>http://java.sun.com/jsf/html</xsl:text>
                          </xsl:attribute>
                           <xsl:attribute name="xmlns:f">
                                <xsl:text>http://java.sun.com/jsf/core</xsl:text>
                           </xsl:attribute>
                           <xsl:attribute name="xmlns:s">
                                <xsl:text>http://jboss.com/products/seam/taglib</xsl:text>
                           </xsl:attribute>
                           <xsl:attribute name="xmlns:c">
                                <xsl:text>http://java.sun.com/jstl/core</xsl:text>
                           </xsl:attribute>
                           <xsl:attribute name="xmlns:rich">
                                <xsl:text>http://richfaces.org/rich</xsl:text>
                           </xsl:attribute>
                           <xsl:attribute name="xmlns:a4j">
                                <xsl:text>http://richfaces.org/a4j</xsl:text>
                           </xsl:attribute>
                           
                           <xsl:apply-templates/>     
                      </xsl:element>
                 </xsl:template>
                 
                 <xsl:template match='mercado'>
                      <xsl:element name="ui:define">
                           <xsl:attribute name="name">
                                <xsl:text>body</xsl:text>
                           </xsl:attribute>
                           
                           <xsl:element name="meta">
                                <xsl:attribute name="http-equiv">
                                     <xsl:text>Content-Type</xsl:text>
                                </xsl:attribute>
                                <xsl:attribute name="content">
                                     <xsl:text>text/html; charset=utf-8</xsl:text>
                                </xsl:attribute>
                           </xsl:element>
                           <xsl:element name="link">
                                <xsl:attribute name="href">
                                     <xsl:text>#{facesContext.externalContext.requestContextPath}/resources/modVisorHistoriaClinica/styles/stylesheet.css</xsl:text>
                                </xsl:attribute>
                                <xsl:attribute name="rel">
                                     <xsl:text>stylesheet</xsl:text>
                                </xsl:attribute>
                                <xsl:attribute name="type">
                                     <xsl:text>text/css</xsl:text>
                                </xsl:attribute>
                           </xsl:element>
                           <xsl:element name="script">
                                <xsl:attribute name="type">
                                     <xsl:text>text/javascript</xsl:text>
                                </xsl:attribute>
                                
                                <xsl:text>setContentTitle('#{messages["Datos de la investigacion"]}')</xsl:text>
                           </xsl:element>               
                             <xsl:element name="h:form">
                                  <xsl:attribute name="id">
                                       <xsl:text>idForm</xsl:text>
                                  </xsl:attribute>
                                <xsl:apply-templates select='tienda'/>
                           </xsl:element>               
                      </xsl:element>          
                 </xsl:template>           
                 
                 <xsl:template match='tienda'>
                           <h4>
                                Nombre:
                                <xsl:value-of select='nombre' />
                                <br/>
                                Tel&#233;fono:
                                <xsl:value-of select='telefono'/>
                                <br/>
                                Nuestros mejores productos
                           </h4>
                           <xsl:element name="rich:table">
                                <xsl:attribute name="styleClass">
                                     <xsl:text>tablaListado</xsl:element>
                                </xsl:attribute>
                                <xsl:element name="tr">
                                     <xsl:attribute name="class">
                                          <xsl:text>normalText</xsl:text>
                                     </xsl:attribute>
                                     <xsl:element name="td">
                                          <xsl:text>C&#243;digo</xsl:text>
                                     </xsl:element>                    
                                     <xsl:element name="td">
                                          <xsl:text>Existencias</xsl:text>
                                     </xsl:element>
                                     <xsl:element name="td">
                                          <xsl:text>Art&#237;culo</xsl:text>
                                     </xsl:element>
                                </xsl:element>                    
                                <xsl:apply-templates select='producto'/>
                           </table>
                 </xsl:template>

                 <xsl:template match='producto'>
                      <xsl:element name="tr">
                           <xsl:apply-templates />
                      </xsl:element>
                 </xsl:template>

                 <xsl:template match='codigo|cantidad|articulo'>
                      <xsl:element name="td">
                           <xsl:value-of select="."/>
                      </xsl:element>
                 </xsl:template>
            </xsl:stylesheet>
            • 3. Re: How to display an XML file transformed by XSL SS file with seam?
              Nikos Paraskevopoulos Novice

              OK, the first question is do you really need on-the-fly transformations? It would be much simpler if the Facelets could be generated from a XSL transformation at deploy time.


              If not, could it be that you can create your views in a standard way? I mean your sample XML is a list. How is this list created? If you are using Java objects (e.g. JPA), you can pass the list that is used to create the XML to JSF directly and create a <dataTable>.


              If you are using something else, e.g. XML database or web service call to obtain the XML, it would be much easier to develop a custom javax.el.ELResolver that will transform expressions like #{mercado.tienda.nombre} to DOM tree walks that will fetch the results from the XML.


              If none of the above applies you would have to tweak or extend com.sun.facelets.FaceletViewHandler to perform the XSL transform before reading the .xhtml and every time it reads the .xhtml, i.e. disable caching. This would affect performance too.


              I strongly suggest investigating whether you can use Java objects and EL. If not, investigate the custom javax.el.ELResolver.

              • 4. Re: How to display an XML file transformed by XSL SS file with seam?
                Vladimir Guerra Miller Newbie

                Well, The problem is that I send you a simple example that I was doing just as a proof, but it isn´t my really data structure, for that reason I can´t work with the bean objects, because I have all the information store at xml files and all of them weren´t create by me, they could be receive from others applications who works with my xml structure.


                Beside, my xml files doesn´t contain the same information, that´s why I tried to generate their views so generic and dynamic as I could, that´s why xsl. To get the xml tags and create the richfaces components from those tags.

                • 5. Re: How to display an XML file transformed by XSL SS file with seam?
                  Ronald van Kuijk Apprentice

                  Use XForms (e.g. Chiba, I do to for complex XML based 'message' structures that need to be displayed and posted in a browser

                  • 6. Re: How to display an XML file transformed by XSL SS file with seam?
                    Ronald van Kuijk Apprentice

                    Ah, and if you want to do it, you could create a custom resource resolver. Name your files e.g. with the extension 'form' like myComplexForm.form. but do not configure seam/jsf/facelets to resolve those, make sure the custom resolver first let's the super do its thing. You do access this from the front like myComplexForm.seam, but it will not find myComplexForm.xhtml based on the fact that it does not exists. Next in your custom resolver retrieve the myComplexForm.form (do some extension translation) and you can transform that with any xsl you like in that resolver. After that it will be passed on to the facelets/jsf layers et voila...

                    • 7. Re: How to display an XML file transformed by XSL SS file with seam?
                      Nikos Paraskevopoulos Novice

                      Vladimir,


                      Since your data is XML, you can try the ELResolver if you want to go with JSF. Otherwise you can try the excellent pointer from Ronald (XForms-Chiba).


                      Ronald, the other pointer (custom resource resolver) is very interesting too. However digging into Facelets code, I am not sure if it is a straightforward solution for this case. The custom resource resolvers transform a string to a java.net.URL object. Then the com.sun.facelets.impl.DefaultFaceletFactory creates the Facelet and caches it. Vladimir would need to tweak this behaviour to create the contents of the URL on the fly (XSLT) and disable caching.

                      • 8. Re: How to display an XML file transformed by XSL SS file with seam?
                        Ronald van Kuijk Apprentice

                        Vladimir,


                        It is a solution since it works for me (not with xsl, but but still). And yes, the URL object is the key thing. Therefore I'll post my complete (unpolished but working) code.


                        The resolver, configure this in the web.xml


                        package nl.fortythree.traha.console.facelets;
                        
                        import java.net.MalformedURLException;
                        import java.net.URL;
                        
                        import com.sun.facelets.impl.DefaultResourceResolver;
                        import com.sun.facelets.impl.ResourceResolver;
                        
                        public class CustomResourceResolver extends DefaultResourceResolver implements ResourceResolver {
                        
                          URL resourceUrl = null;
                        
                          @Override
                          public URL resolveUrl(String resource) {
                        
                        
                             resourceUrl = super.resolveUrl(resource);
                             if (resourceUrl == null) {
                               if (resource.startsWith("/")) {
                                  resource = resource.substring(1);
                                    try {
                                              // Use real factory...  hmm...should I? Don't think I do.
                                       resourceUrl = new URL(null, "jbpm:"+resource, new JbpmStreamHandlerFactory().createURLStreamHandler("jbpm"));
                                    } catch (MalformedURLException e) {
                                       // TODO Fix exceptionhandling
                                       e.printStackTrace();
                                    }
                               }
                             }
                             return resourceUrl;
                          }
                        }



                        The streamhandler factory:


                        package nl.fortythree.traha.console.facelets;
                        
                        import java.net.*;
                        
                        // TODO Not fully a factory yet, change this 
                        public class JbpmStreamHandlerFactory implements URLStreamHandlerFactory {
                          
                           public URLStreamHandler createURLStreamHandler(String protocol) {
                          
                            if (protocol.equalsIgnoreCase("jbpm")) {
                              return new JbpmProtocolHandler();
                            }
                            else {
                              return null;
                            }
                          }
                        }



                        The protocol handler:



                        package nl.fortythree.traha.console.facelets;
                        
                        import java.io.IOException;
                        import java.net.URL;
                        import java.net.URLConnection;
                        import java.net.URLStreamHandler;
                        
                        public class JbpmProtocolHandler extends URLStreamHandler {
                        
                          @Override
                          protected URLConnection openConnection(URL u) throws IOException {
                             return new JbpmURLConnection(u);
                          }
                        }



                        The URL connection. This does the real work in my case by reading the form from the jBPM process repository. Adapt to your needs. Still needs refinement but it does work (I'll blog about this later this month)



                        package nl.fortythree.traha.console.facelets;
                        
                        import java.net.*;
                        import java.util.Date;
                        import java.io.*;
                        
                        import org.apache.commons.io.IOUtils;
                        import org.jbpm.JbpmConfiguration;
                        import org.jbpm.JbpmContext;
                        import org.jbpm.file.def.FileDefinition;
                        
                        public class JbpmURLConnection extends URLConnection {
                        
                          JbpmContext               jBPMContext;
                        
                          private FileDefinition fd;
                          private String           form;
                          private String           content = null;
                        
                          public JbpmURLConnection(URL u) {
                             super(u);
                          }
                        
                          @Override
                          public synchronized InputStream getInputStream() throws IOException {
                        
                             if (!connected) connect();
                        
                             if (content != null) { 
                               return IOUtils.toInputStream(content);
                             } else {
                               return null;
                             }
                        
                          }
                        
                          public String getContentType() {
                             return "text/html";
                          }
                        
                          public synchronized void connect() throws IOException {
                        
                             if (!connected) {
                               
                               
                               String pd = url.getPath().substring(0, url.getPath().indexOf("/"));
                               
                               //Strip processdefinition id from the path
                               this.form = url.getFile().substring(url.getFile().indexOf("/")+1);
                        
                               
                               jBPMContext = JbpmConfiguration.getInstance().createJbpmContext();
                        
                               fd = jBPMContext.getGraphSession().getProcessDefinition(Long.parseLong(pd)).getFileDefinition();
                               InputStream result = fd.getInputStream(this.form);
                        
                               if (result != null) {
                                  content = IOUtils.toString(result);
                               }
                               
                               if (jBPMContext != null) {
                                  jBPMContext.close();
                               }
                        
                               this.connected = true;
                             }
                          }
                        
                          /*
                           * Pages from the DB currently never expire since they have a version number in the 'cache' 
                           * because we create the dummy page name from the processDefinition id and the task name 
                           * 
                           * (non-Javadoc)
                           * @see java.net.URLConnection#getExpiration()
                           */
                          @Override
                          public long getExpiration() {
                             return -1l;
                          }
                        
                          @Override
                          public long getLastModified() {
                             return -1l;
                          }
                        }



                        It is a strange implementation of a URLConnection, mainly due to the fact that the data comes from a database and otherwise I get inputstream closed exceptions. So do not pay attention to that to much :-) You'll get the idea.


                        If you leave out the getExperation method and getLastModified method, there is no caching of this facelet since it the default URLConnection has this set to 0. -1 defines that it cached indefinately as can be done with deployed processdefinitions since versioning takes place at the processdefinitionlevel atm.

                        • 9. Re: How to display an XML file transformed by XSL SS file with seam?
                          Nikos Paraskevopoulos Novice

                          That was VERY interesting Ronald! Could definitely work for Vladimir's case.

                          • 10. Re: How to display an XML file transformed by XSL SS file with seam?
                            Vladimir Guerra Miller Newbie

                            Thanks my friend, I'll try this and then I'll notify you.
                            Thanks a lot.