Index: main/plugin-web/src/org/ametys/web/frontoffice/AbstractSearchGenerator.java
===================================================================
--- main/plugin-web/src/org/ametys/web/frontoffice/AbstractSearchGenerator.java	(revision 29187)
+++ main/plugin-web/src/org/ametys/web/frontoffice/AbstractSearchGenerator.java	(working copy)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Anyware Services
+ *  Copyright 2015 Anyware Services
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Pattern;
 
 import org.apache.avalon.framework.context.Context;
@@ -38,6 +39,7 @@
 import org.apache.cocoon.generation.ServiceableGenerator;
 import org.apache.cocoon.xml.AttributesImpl;
 import org.apache.cocoon.xml.XMLUtils;
+import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.br.BrazilianAnalyzer;
@@ -66,9 +68,17 @@
 
 import org.ametys.cms.contenttype.ContentType;
 import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
+import org.ametys.cms.contenttype.MetadataDefinition;
+import org.ametys.cms.contenttype.MetadataDefinitionReference;
+import org.ametys.cms.contenttype.MetadataSet;
+import org.ametys.cms.contenttype.MetadataSetElement;
+import org.ametys.cms.contenttype.MetadataType;
+import org.ametys.cms.contenttype.RepeaterDefinition;
 import org.ametys.plugins.explorer.dublincore.DublinCoreMetadataProvider;
 import org.ametys.plugins.repository.AmetysObjectResolver;
+import org.ametys.plugins.repository.AmetysRepositoryException;
 import org.ametys.runtime.util.I18nizableText;
+import org.ametys.runtime.util.parameter.Enumerator;
 import org.ametys.runtime.util.parameter.ParameterHelper;
 import org.ametys.web.lucene.FieldNames;
 import org.ametys.web.lucene.IndexTermCache;
@@ -89,7 +99,7 @@
 {
     /** Textfield pattern */
     protected static final Pattern _TEXTFIELD_PATTERN = Pattern.compile("^[^?*].*$");
-
+    
     /** The {@link ContentType} manager */
     protected ContentTypeExtensionPoint _cTypeExtPt;
     /** The sites manager */
@@ -577,8 +587,9 @@
      * @param doc the document
      * @param index the search index
      * @throws SAXException If an error occurs while SAXing
+     * @throws ProcessingException 
      */
-    protected void saxPageHit (TopDocs rs, Document doc, int index) throws SAXException
+    protected void saxPageHit (TopDocs rs, Document doc, int index) throws SAXException, ProcessingException
     {
         float score = rs.scoreDocs[index].score;
         float maxScore = rs.getMaxScore();
@@ -588,7 +599,20 @@
         XMLUtils.createElement(contentHandler, "score", Float.toString(score));
         XMLUtils.createElement(contentHandler, "percent", Integer.toString(percent));
         XMLUtils.createElement(contentHandler, "title", doc.get(LONG_TITLE));
-
+        
+        String[] contentTypes = doc.getValues(CONTENT_TYPES);
+        if (ArrayUtils.isNotEmpty(contentTypes))
+        {
+            for (String contentType : contentTypes)
+            {   
+                XMLUtils.startElement(contentHandler, "content");
+                
+                _saxContentMetadatas(contentType, doc);
+                
+                XMLUtils.endElement(contentHandler, "content");
+            }
+        }
+        
         String[] contentNames = doc.getValues(CONTENT_NAMES);
         for (String contentName : contentNames)
         {
@@ -654,7 +678,7 @@
             XMLUtils.createElement(contentHandler, "latitude", latLng[0]);
             XMLUtils.createElement(contentHandler, "longitude", latLng[1]);
         }
-
+        
         saxAdditionalInfosOnPageHit (doc);
 
         XMLUtils.endElement(contentHandler, "hit");
@@ -665,10 +689,7 @@
      * @param doc the document
      * @throws SAXException
      */
-    protected void saxAdditionalInfosOnPageHit (Document doc) throws SAXException
-    {
-        // Nothing
-    }
+    protected abstract void saxAdditionalInfosOnPageHit (Document doc) throws SAXException;
 
     /**
      * SAX a hit of type {@link FieldNames}.TYPE_PAGE
@@ -1006,13 +1027,221 @@
         }
         return valid;
     }
+    
+    /**
+     * Sax the list of metadata paths of the content type
+     * @param contentTypeId the id of the content type 
+     * @param document the lucene document
+     * @throws ProcessingException if a processing exception occurs
+     * @throws SAXException if an exception occurs while saxing
+     */
+    private void _saxContentMetadatas(String contentTypeId, Document document) throws ProcessingException, SAXException
+    {   
+        ContentType contentType = _cTypeExtPt.getExtension(contentTypeId);
+        MetadataSet metadataSet = contentType.getMetadataSetForView("index");
+        
+        // No metadata set index defined => do not sax rich texts
+        if (metadataSet == null)
+        {
+            return; 
+        }
+
+        _saxMetadataSetElements("", contentType, null, metadataSet, document);
+    }
+
+    /**
+     * Sax recursively the paths of the metadatas of the metadata set 
+     * @param prefix the prefix of the metadata path
+     * @param contentType the content type
+     * @param metadataDefinition the metadata definition
+     * @param metadataSetElement the metadata set element
+     * @param document the lucene document
+     * @throws SAXException if an exception occurs
+     */
+    private void _saxMetadataSetElements(String prefix, ContentType contentType, MetadataDefinition metadataDefinition, MetadataSetElement metadataSetElement, Document document) throws SAXException
+    {
+        for (MetadataSetElement subMetadataSetElement : metadataSetElement.getElements())
+        {
+            MetadataDefinitionReference metadataDefRef = (MetadataDefinitionReference) subMetadataSetElement;
+            String metadataName = metadataDefRef.getMetadataName();
+            MetadataDefinition childMetadataDefinition = _getMetadataDefinition(contentType, metadataDefinition, metadataName);
+            
+            if (childMetadataDefinition == null)
+            {
+                throw new IllegalArgumentException("Unable to get the metadata definition for metadata with name '" + metadataName + "' (" + contentType.getId() + ").");
+            }
+
+            Set<String> childMetadataNames = childMetadataDefinition.getMetadataNames();
+            if (childMetadataNames.isEmpty())
+            {
+                String path = prefix + metadataName;
+                Enumerator enumerator = childMetadataDefinition.getEnumerator();
+                if (childMetadataDefinition.getType().equals(MetadataType.FILE) || childMetadataDefinition.getType().equals(MetadataType.BINARY))
+                {
+                    AttributesImpl attrs = new AttributesImpl();
+                    _addAttribute(document, "path", path + "$path", attrs);
+                    _addAttribute(document, "type", path + "$type", attrs);
+                    _addAttribute(document, "mime-type", path + "mime-type", attrs);
+                    _addAttribute(document, "filename", path + "$filename", attrs);
+                    _addAttribute(document, "lastModified", path + "$lastModified", attrs);
+                    _addAttribute(document, "size", path + "$size", attrs);
+                    _addAttribute(document, "viewUrl", path + "$viewUrl", attrs);
+                    _addAttribute(document, "downloadUrl", path + "$downloadUrl", attrs);
+
+                    XMLUtils.createElement(contentHandler, metadataName, attrs);
+                }
+                else if (enumerator != null) 
+                {
+                    _saxEnumeratedStringMetadata(document, metadataName, path, enumerator);
+                }
+                else
+                {
+                    _saxMetadata(document, metadataName, path);
+                }
+            }
+            else
+            {
+                XMLUtils.startElement(contentHandler, metadataName);
+                
+                if (childMetadataDefinition instanceof RepeaterDefinition)
+                {
+                    String sizeStr = document.get(prefix + metadataName + "/size");
+                    if (StringUtils.isNotEmpty(sizeStr))
+                    {
+                        for (int i = 0; i < Integer.parseInt(sizeStr); i++)
+                        {
+                            AttributesImpl attrs = new AttributesImpl();
+                            attrs.addCDATAAttribute("name", Integer.toString(i + 1));
+                            
+                            XMLUtils.startElement(contentHandler, "entry", attrs);
+                            
+                            _saxMetadataSetElements(prefix + metadataName + "/" + Integer.toString(i + 1) + "/", contentType, childMetadataDefinition, subMetadataSetElement, document);
+                           
+                            XMLUtils.endElement(contentHandler, "entry");
+                        }
+                    }
+                }
+                else
+                {
+                    _saxMetadataSetElements(prefix + metadataName + "/", contentType, childMetadataDefinition, subMetadataSetElement, document);
+                }
+                    
+                XMLUtils.endElement(contentHandler, metadataName);
+            }
+        }
+    }
+
+    /**
+     * Add an attribute to a tag if its value is not null
+     * @param document the lucene document
+     * @param name the name of the attribute
+     * @param path the path of the metadata
+     * @param attrs the attributes
+     */
+    protected void _addAttribute(Document document, String name, String path, AttributesImpl attrs)
+    {
+        String value = document.get(path);
+        if (value != null)
+        {
+            attrs.addCDATAAttribute(name, value);
+        }
+    }
+
+    /**
+     * Sax a metadata
+     * @param document the lucene document
+     * @param metadataName the name of the metadata
+     * @param path the path of the metadata
+     * @throws SAXException if an exception occurs
+     */
+    private void _saxMetadata(Document document, String metadataName, String path) throws SAXException
+    {
+        String value = document.get(path);
+        if (value != null)
+        {
+            XMLUtils.createElement(contentHandler, metadataName, value);
+        }
+    }
+    
+    /**
+     * SAX a metadata as a enumerated String.
+     * @param document the lucene document
+     * @param metadataName the metadata name.
+     * @param path the lucene index
+     * @param enumerator the enumerator
+     * @throws AmetysRepositoryException if an error occurs.
+     * @throws SAXException if an error occurs.
+     */
+    protected void _saxEnumeratedStringMetadata (Document document, String metadataName, String path, Enumerator enumerator) throws SAXException
+    {
+        String luceneValue = document.get(path);
+        
+        if (luceneValue != null)
+        {
+            String[] values = StringUtils.split(luceneValue, ',');
+        
+            for (String value : values)
+            {
+                if (StringUtils.isEmpty(value))
+                {
+                    XMLUtils.createElement(contentHandler, metadataName);
+                }
+                else
+                {
+                    try
+                    {
+                        I18nizableText i18n = enumerator.getEntry(value);
+                        if (i18n != null)
+                        {
+                            AttributesImpl attrs = new AttributesImpl();
+                            attrs.addCDATAAttribute("value", value);
+                            
+                            XMLUtils.startElement(contentHandler, metadataName, attrs);
+    
+                            i18n.toSAX(contentHandler);
+                            
+                            XMLUtils.endElement(contentHandler, metadataName);
+                        }
+                        else
+                        {
+                            AttributesImpl attrs = new AttributesImpl();
+                            attrs.addCDATAAttribute("value", value);
+                            
+                            XMLUtils.createElement(contentHandler, metadataName, attrs, value);
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        getLogger().warn("An error occurred while saxing the enumerated metadata '" + metadataName + "'.", e);
+    
+                        AttributesImpl attrs = new AttributesImpl();
+                        attrs.addCDATAAttribute("value", value);
+                        
+                        XMLUtils.createElement(contentHandler, metadataName, attrs, value);
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Retrieves a sub metadata definition from a content type or
+     * a parent metadata definition. 
+     * @param contentType the content type.
+     * @param parentMetadataDefinition the parent metadata definition.
+     * @param metadataName the metadata name.
+     * @return the metadata definition found or <code>null</code> otherwise.
+     */
+    private MetadataDefinition _getMetadataDefinition(ContentType contentType, MetadataDefinition parentMetadataDefinition, String metadataName)
+    {
+        return parentMetadataDefinition == null ? contentType.getMetadataDefinition(metadataName) : parentMetadataDefinition.getMetadataDefinition(metadataName);
+    }
 
     /**
      * Criterion class.
      */
     protected class Criterion
     {
-
         /** Form field name. */
         protected String _fieldName;
 
@@ -1165,7 +1394,5 @@
         {
             this._values = values;
         }
-
     }
-
 }
Index: main/plugin-web/src/org/ametys/web/frontoffice/SearchGenerator.java
===================================================================
--- main/plugin-web/src/org/ametys/web/frontoffice/SearchGenerator.java	(revision 29187)
+++ main/plugin-web/src/org/ametys/web/frontoffice/SearchGenerator.java	(working copy)
@@ -27,6 +27,7 @@
 import java.util.Set;
 import java.util.regex.Matcher;
 
+import org.apache.cocoon.ProcessingException;
 import org.apache.cocoon.environment.Request;
 import org.apache.cocoon.xml.AttributesImpl;
 import org.apache.cocoon.xml.XMLUtils;
@@ -299,7 +300,14 @@
             
             if (TYPE_PAGE.equals(doc.get(TYPE)))
             {
-                saxPageHit(rs, doc, i);
+                try 
+                {
+                    saxPageHit(rs, doc, i);
+                }
+                catch (ProcessingException e)
+                {
+                    getLogger().error("An exception occurred while saxing the page hits", e);
+                }
             }
             else if (TYPE_RESOURCE.equals(doc.get(TYPE)))
             {
@@ -914,4 +922,10 @@
             query.add(pageQuery, BooleanClause.Occur.MUST);
         }
     }
+
+    @Override
+    protected void saxAdditionalInfosOnPageHit(Document doc) throws SAXException
+    {
+        // Nothing
+    }
 }
Index: main/plugin-web/src/org/ametys/web/frontoffice/SearchResourcesGenerator.java
===================================================================
--- main/plugin-web/src/org/ametys/web/frontoffice/SearchResourcesGenerator.java	(revision 29187)
+++ main/plugin-web/src/org/ametys/web/frontoffice/SearchResourcesGenerator.java	(working copy)
@@ -499,4 +499,10 @@
             query.add(rightsQuery, BooleanClause.Occur.MUST);
         }
     }
+
+    @Override
+    protected void saxAdditionalInfosOnPageHit(Document doc) throws SAXException
+    {
+        // Nothing
+    }
 }
