Páginas

miércoles, 13 de febrero de 2013

Primeros pasos con JSON y Java

Introducción

JSON (JavaScript Object Notation), es un formato estándar de intercambio de datos basado en texto que permite a las aplicaciones intercambiar información.

JSON está estandarizado por la IETF (Internet Engineering Task Force) en el RFC-4627 (http://tools.ietf.org/html/rfc4627). El Mime Type para datos en éste formato es 'application/json' y la extensión oficial de los ficheros con este formato es '.json'.

Los datos intercambiados son independientes tanto de la plataforma como del lenguaje de programación utilizado.

¿Qué ventajas ofrece JSON frente a XML?

JSON va reemplazando a XML poco a poco como medio preferido a la hora de intercambiar datos entre aplicativos de distintas plataformas. Los motivos por los que se argumenta que JSON es mejor son casi siempre los mismos:
  • JSON es más fácil de leer (xml también).
  • JSON tiene una estructura es similar a la de Objetos y Arrays (xml también).
  • JSON es más ligero (bytes) en las transmisiones (desde luego que no hay etiqueta de cierre, pero sí de apertura).
  • JSON se parsea más rápido (supongo que será verdad, pero entiendo que dependerá de la calidad del parseador).

Sintaxis JSON

En este apartado vamos a repasar las principales características de la sintaxis JSON, se puede encontrar fácilmente documentación detallada sobre el tema, por ejemplo en el enlace siguiente: http://www.json.org

Estructuras de datos en JSON

JSON ofrece únicamente tres estructuras de datos:
   
- Pares Nombre/Valor. Un ejemplo sería:
   
            {
                "nombre" : "nombre11"
            }

           
- Objetos. Son colecciones desordenadas de pares Nombre/Valor. Un ejemplo sería:
       
            {
                "contacto" : {
                    "nombre" : "nombre11",
                    "apellido1" : "apellido11",
                    "apellido2" : "apellido21",
                    "email" : "11111111@gmail.com"
                }
            }

           
- Arrays. Son colecciones ordenadas de objetos. Un ejemplo sería:
           
            {
                "agenda" : [
                    {"nombre" : "nombre11", "apellido1" : "apellido11", "apellido2" : "apellido21", "email" : "11111111@gmail.com"},
                    {"nombre" : "nombre12", "apellido1" : "apellido12", "apellido2" : "apellido22", "email" : "22222222@gmail.com"},
                    {"nombre" : "nombre13", "apellido1" : "apellido13", "apellido2" : "apellido23", "email" : "33333333@gmail.com"}
                ]
            }

Tipos de datos en JSON

Hasta el momento hemos visto que en la parte derecha de cada par "Nombre/Valor" aparecía siempre una cadena entrecomillada. JSON admite además de cadenas (String) algunos otros tipos de datos:
  • Object
  • Array
  • String
  • Number
  • Boolean
  • null

Comentarios en JSON

JSON no admite comentarios.

Convenciones en el nombrado de atributos

Los nombres de los atributos en JSON (el elemento izquierdo de cada par Nombre/Valor) se escriben en notación "camel case", que es típica también en Java. La idea es escribir los nombres compuestos metiendo mayúscula al comienzo de cada palabra excepto en la primera. Por ejemplo: "telefFijo", "telefMovil", etc.

Esquemas en JSON

Los documentos JSON, como cabría esperar, están basados en esquemas. Los esquemas definen la estructura de los documentos JSON y permiten validarlos. Los esquemas JSON están evolucionando muy rápidamente (la versión 0.4 está publicada en: http://tools.ietf.org/html/draft-zyp-json-schema-04
   
El sitio de internet donde más esquemas JSON hay publicados es: http://json-schema.org, pero visto el número de esquemas ¿estándares? publicados parece que el tema está aún muy verde. Parece que aún está lejos de sustituir al XML en este sentido.

Herramientas para trabajar con JSON

A la hora de empezar a trabajar con JSON pueden ser interesantes las siguientes herramientas:
  • Validador online JSON. Revisar la sintaxis de un documento JSON grande a ojo es verdaderamente pesado, por tanto puede ser interesante utilizar un validador online como el ofrecido en http://www.jsonlint.com para validar nuestros documentos.
  • Editor JSON. Si lo que necesitamos es un editor JSON donde generar documentos o esquemas con cierto nivel de asistencia, una herramienta muy popular es JSONPad, descargable en: http://www.jsonpad.com/en/Home.html. También hay editores online, siendo uno de los más populares: http://jsoneditoronline.org/

JSON y Java

A la hora de programar aplicaciones que generen o traten datos en formato JSON hay muchos API:
  • Jackson. http://jackson.codehaus.org
  • Google GSON. http://code.google.com/p/google-json/
  • SOJO. http://sojo.sourceforge.net/

Aplicativo Java de pruebas

El siguiente proyecto Java muestra un ejemplo de cómo realizar las siguientes operaciones:
  • Crear un documento JSON a partir de un POJO
  • Crear un POJO a partir de un documento JSON
  • Obtener el esquema de un documento JSON
  • Validar un documento JSON contra un esquema   
Se han utilizado las siguientes librerías:

        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-lgpl</artifactId>
            <version>1.9.12</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
            <type>jar</type>
        </dependency>

El código son dos clases, la clase Contacto.java y la clase TestJSON.java:
   
package es.ine.sgtic.pojo;

public class Contacto {

    private String nombre;
    private String apellido1;
    private String apellido2;
    private String telefFijo;
    private String telefMovil;
    private String email;

    public Contacto(){
        //Constructor que precisa JSON
    }
    public Contacto(final String nombre,
            final String apellido1,
            final String apellido2,
            final String telefFijo,
            final String telefMovil,
            final String email) {
        this.nombre = nombre;
        this.apellido1 = apellido1;
        this.apellido2 = apellido2;
        this.telefFijo = telefFijo;
        this.telefMovil = telefMovil;
        this.email = email;
    }
    public String getNombre() {
        return nombre;
    }
    public void setNombre(final String nombre) {
        this.nombre = nombre;
    }
    public String getApellido1() {
        return apellido1;
    }
    public void setApellido1(final String apellido1) {
        this.apellido1 = apellido1;
    }
    public String getApellido2() {
        return apellido2;
    }
    public void setApellido2(final String apellido2) {
        this.apellido2 = apellido2;
    }
    public String getTelefFijo() {
        return telefFijo;
    }
    public void setTelefFijo(final String telefFijo) {
        this.telefFijo = telefFijo;
    }
    public String getTelefMovil() {
        return telefMovil;
    }
    public void setTelefMovil(final String telefMovil) {
        this.telefMovil = telefMovil;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(final String email) {
        this.email = email;
    }

    public boolean equals(Contacto cto) {
        return this.nombre.equals(cto.getNombre()) &&
                this.apellido1.equals(cto.getApellido1()) &&
                this.apellido2.equals(cto.getApellido2()) &&
                this.telefFijo.equals(cto.getTelefFijo()) &&
                this.telefMovil.equals(cto.getTelefMovil()) &&
                this.email.equals(cto.getEmail());
    }
}


package es.ine.sgtic.pojo;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.SerializationConfig.Feature;
import org.codehaus.jackson.schema.JsonSchema;

public class TestJSON {

    private static Log log = LogFactory.getLog(TestJSON.class);
   
    public static void main (String args[]) 

                       throws JsonGenerationException, 
                       JsonMappingException, IOException {

        //Instanciamos el convertidor Java-JSON (funcionaría en ambos sentidos
        final ObjectMapper mapper = new ObjectMapper();

        //Ajustamos el convertidor para que indente las cadenas JSON genedaras
        mapper.configure(Feature.INDENT_OUTPUT, true);

        //Montamos un pojo de la clase Contacto
        final Contacto cto1 = new Contacto("nombre","apellido1","apellido2",

                                  "123456789","987654321","egdp1970@gmail.com");

        log.trace("Generamos el String cadenaJSON asociado al objeto cto1");
        String cadenaJSON = generaNotacionJSON(mapper, cto1);
        log.trace(cadenaJSON);
        log.trace("----------------------------------------------------");
       
        log.trace("Generamos un objeto cto2 a partir del String cadenaJSON");
        final Contacto cto2 = (Contacto)generaPojojava(mapper, cadenaJSON, cto1.getClass());
        log.trace("Comparamos el objeto cto1 y el objeto cto2");
        log.trace("cto1.equals(cto2)-->"+cto1.equals(cto2));
        log.trace("----------------------------------------------------");

        log.trace("Generamos String cadenaJSON asociado al objeto cto2");
        cadenaJSON = generaNotacionJSON(mapper, cto2);
        log.trace(cadenaJSON);
        log.trace("----------------------------------------------------");

        log.trace("Generamos el String schemaJSON asociado al objeto cto1");
        final String schemaJSON = generaSchemaJSON(mapper, cto1.getClass());
        log.trace(schemaJSON);
        log.trace("----------------------------------------------------");

        log.trace("Validamos el String cadenaJSON contra el esquema schemaJSON");
        log.trace("validaCadenaJSON()-->"+validaCadenaJSON(mapper, cadenaJSON));
        log.trace("----------------------------------------------------");
       
        log.trace("Validamos el String cadenaJSON_ERR contra el esquema schemaJSON");
        final String cadenaJSON_ERR = cadenaJSON + "}";
        log.trace("validaCadenaJSON()-->"+validaCadenaJSON(mapper, cadenaJSON_ERR));
        log.trace("----------------------------------------------------");
    }

    private static String generaNotacionJSON(final ObjectMapper mapper, 

                                             Object obj) 
                                              throws JsonGenerationException, 
                                              JsonMappingException, 
                                              IOException{

        //Convertimos el objeto Java en notación JSON
        final Writer writer = new StringWriter();
        mapper.writeValue(writer, obj);

        //Devolvemos la cadena JSON
        return writer.toString();
    }

    private static Object generaPojojava(final ObjectMapper mapper, 

                                         final String cadenaJSON, 
                                         final Class<?> clazz) 
                                              throws JsonGenerationException, 
                                              JsonMappingException, 
                                              IOException{

        //Convertimos la notación JSON en objeto Java
        return mapper.readValue(cadenaJSON, clazz);
    }

    private static String generaSchemaJSON(final ObjectMapper mapper, 

                                           final Class<?> clazz)                                                                      throws JsonGenerationException, 
                                              JsonMappingException, 
                                              IOException{

        //Generamos el schema JSON para el pojo
        final SerializationConfig cfg = mapper.getSerializationConfig();
        final JsonSchema jsonSchema = mapper.generateJsonSchema(clazz,cfg);
        return jsonSchema.toString();
    }

    private static boolean validaCadenaJSON(final ObjectMapper mapper, 

                                            final String cadenaJSON){

        boolean valido = false;
        try {
            final JsonParser parser = mapper.getJsonFactory().createJsonParser(cadenaJSON);
            while (parser.nextToken() != null) {
            }
            valido = true;
        } catch (JsonParseException e) {
           
//log.error(e.getMessage(),e);
        } catch (IOException e) {
           
//log.error(e.getMessage(),e);
        }

        return valido;
    }
}

lunes, 4 de febrero de 2013

Primeros pasos con Apache Lucene

Introducción

Lucene es un motor de búsqueda de Apache. Está implementado en Java (http://lucene.apache.org) y es usado en multitud de gestores de contenido.

Lucene indexa texto, no trabaja directamente sobre ningún formato de fichero concreto. Por tanto, para indexar "documentos",  previamente deberá extraerse su contenido con las librerías adecuadas.

Dado cualquier texto, Luceneindexa por defecto las primeras 1000 palabras.

Algunas librerías típicas para menejar los documentos más comunes son:

    PDF. JPedal (http://www.jpedal.org/).
    Microsoft Word, Excel, Visio y Power Point. Apache POI (http://poi.apache.org/)
    OpenOffice. LIUS (http://www.bibl.ulaval.ca/lius/).
    RTF. Swing RTFEditorKit class.

Una vez indexado el contenido de un "documento", se podrán efectuar búsquedas sobre los índices generados. Al efectuarse las búsquedas sobre los índices estas son siempre más rápidas que búsquedas sobre los "documentos".

Componentes de Lucene

En Lucene trabaja con tres conceptos esenciales:
  • Documentos. Un documento, para Lucene, es una tupla de N campos. Cada campo tiene un nombre y contiene cierto tipo de información.
  • Campos. Es cada una de las categorías de información que componen el documento.
  • Querys. Para realizar las búsquedas en el índice, Lucene ofrece un lenguaje de consultas, que permite especificar en qué campos buscar, admite comodines, admite AND, OR y NOT, admite búsquedas por proximidad, etc.
Veamos por ejemplo un par de "documentos":
  • Agenda. En una agenda de contactos, un documento sería cada una de las fichas de la agenda. Los campos serían, por ejemplo, el nombre, el primer apellido, el segundo apellido, el teléfono móvil, el teléfono fijo, etc
  • Biblioteca. En una biblioteca, un documento sería cada uno de los libros. Los campos serían, por ejemplo: título, autor, estantería, contenido, ISBN, etc.
Veamos por ejemplo algunas querys en el índice de la biblioteca:
  • Lista de libros donde el autor sea "Phillip"
        autor:Phillip
  • Lista de libros donde el autor sea "Philip K Dick"
        autor:"Philip K Dick"
  • Lista de libros donde el autor sea "Philip K Dick", en el contenido del libro aparezca "ovejas"
        autor:"Philip K Dick" AND contenido:ovejas

Apliación Java de ejemplo

Hemos montado un proyecto Maven2 con las siguientes dependencias:

  <dependencies>
      <dependency>
          <groupId>org.apache.lucene</groupId>
          <artifactId>lucene-core</artifactId>
          <version>4.0.0</version>
      </dependency>
      <dependency>
          <groupId>org.apache.lucene</groupId>
          <artifactId>lucene-queryparser</artifactId>
          <version>4.0.0</version>
      </dependency>
      <dependency>
          <groupId>org.apache.lucene</groupId>
          <artifactId>lucene-analyzers-common</artifactId>
          <version>4.0.0</version>
      </dependency>
      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-io</artifactId>
          <version>1.3.2</version>
      </dependency>
  </dependencies>


Adjuntamos un ejemplo en Java donde se montará el índice de una biblioteca, añadiendo varios documentos y efectuando algunas búsquedas.

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;

public class AppTest {

    public static void main(String[] args) throws IOException, ParseException, InvalidTokenOffsetsException {

        //Fijamos el analizador para tokenizar, indezar y buscar en textos
        final StandardAnalyzer analizador = new StandardAnalyzer(Version.LUCENE_40);

        //Creamos el indice en memoria RAM 

        final Directory indice = new RAMDirectory();
        final IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_40, analizador);

        //Montamos el generador del índice
        final IndexWriter iw = new IndexWriter(indice, config);

        //Nuestros documentos serán libros con tres campos: titulo, autor y contenido.
        //Añadimos un par de libros, los ficheros txt con el contenido de los mismos están en el classpath
        addLibro(iw, "El ingenioso hidalgo Don Quijote de la Mancha", "Miguel de Cervantes y Saavedra", new File("Quijote.txt"));
        addLibro(iw, "El Buscón", "Francisco Gómez de Quevedo y Santibáñez Villegas", new File("Buscon.txt"));
 

        //Cerramos el generador de índice
        iw.close();

        //Lanzamos algunas querys
        lanzaConsulta(analizador, indice, "autor:Cervantes");
        lanzaConsulta(analizador, indice, "autor:\"de Cervantes y\"");
        lanzaConsulta(analizador, indice, "autor:Cervan*");
        lanzaConsulta(analizador, indice, "autor:Cervantes AND titulo:hidalgo");
        lanzaConsulta(analizador, indice, "autor:Cervantes OR autor:Quevedo");
        lanzaConsulta(analizador, indice, "(autor:Cervantes OR autor:Quevedo) AND NOT titulo:Quijote");


        //Algunas querys de búsqueda por proximidad, esto es palabras parecidas a la nuestra 
        //pudiendo diferenciase en N caracteres
        lanzaConsulta(analizador, indice, "contenido:Tocoso~1"); //Buscamos a Dulcinea del "Tocoso" sabiendo que es algo parecido
    }

    private static void addLibro(final IndexWriter iw, 

                                                  final String titulo, 
                                                  final String autor, 
                                                  final File f) throws Exception {

        //Montamos el documento
        final Document libro = new Document();

        //Le añadimos el atributo titulo
        libro.add(new TextField("titulo", titulo, Field.Store.YES));

        //Le añadimos el atributo autor
        libro.add(new TextField("autor", autor, Field.Store.YES));

        //Le añadimos el atributo contenido
        libro.add(new TextField("contenido", new FileReader(f)));

        //Le añadimos la ubicacion del fichero
        libro.add(new TextField("fichero", f.getCanonicalPath(), Field.Store.YES));

        //Damos de alta el documento
        iw.addDocument(libro);
    }


    private static void lanzaConsulta(final StandardAnalyzer analizador, 

                                                           final Directory indice, 
                                                           final String query) throws ParseException, IOException {

        //Montamos el parseador de Querys. El segundo parámetro es el campo por defecto donde
        //se realizarán las búsquedas si una query no indica ningún campo concreto
        final QueryParser queryParser = new QueryParser(Version.LUCENE_40, "titulo", analizador);
        final Query q = queryParser.parse(query);

        //Montamos el buscador
        final IndexReader reader = DirectoryReader.open(indice);
        final IndexSearcher searcher = new IndexSearcher(reader);

        //Lanzamos la query
        final int numMaxResults = 10;
        final TopDocs docsEncontrados = searcher.search(q,numMaxResults);   
        System.out.println("Total hits "+docsEncontrados.totalHits);

        //Recuperamos la lista de coincidencias
        final ScoreDoc[] docs = docsEncontrados.scoreDocs;

        //Mostramos los resultados
        System.out.println("-------------------------------------------------------------------");
        System.out.println("Encontradas " + docsEncontrados.totalHits + " coincidencias para '"+query);
        int idDoc;
        int index;
        float score;
        Document doc;
        for(int i=0;i<docs.length;++i) {
            idDoc = docs[i].doc;
            score = docs[i].score;
            index = docs[i].shardIndex;
            doc = searcher.doc(idDoc);
            System.out.println(String.format("%d. [%f] \t %s \t %s",index,score,doc.get("titulo"),doc.get("autor")));
        }
        System.out.println("-------------------------------------------------------------------");
    }
}


Enlaces de interés

http://wiki.apache.org/lucene-java/LuceneFAQ
http://www.lucenetutorial.com/

viernes, 18 de enero de 2013

Instalación y pruebas de Solr 4.0.0 en Tomcat

Introducción

Solr es un motor de búsqueda de código abierto basado en la biblioteca Java del proyecto Lucene. Ejecuta sobre un contenedor de servlets, como por ejemplo Apache Tomcat.

La finalidad de Solr es tener un motor de búsqueda interno en nuestro servidor.

Descarga Apache Solr

http://www.eu.apache.org/dist/lucene/solr/4.0.0/apache-solr-4.0.0.tgz

Instalación de Solr 4.0.0 en Apache Tomcat

Para instalar Solr 4.0.0 en Apache Tomcat los pasos a seguir son los siguientes:

1) Descomprimimos el fichero apache-solr-4.0.0.tgz en alguna ubicación de nuestro disco duro, por ejemplo en /home/xxxxxxx/temp/apache-solr-4.0.0
2) Recuperamos el war del directorio dist/apache-solr-4.0.0.war
3) Renombramos el fichero apache-solr-4.0.0.war a solr.war
4) Movemos el fichero solr.war a la carpeta webapps de nuestro tomcat
5) Solr necesita un directorio de trabajo que podemos colocar en cualquier ubicación, en este ejemplo supondremos /home/xxxxxxx/solr
6) Volcamos en la carpeta anterior el contenido de /home/xxxxxxx/temp/apache-solr-4.0.0/example/solr.
7) Tras este volcado, en nuestra carpeta /home/xxxxxxx/solr tendremos:

drwxr-xr-x 2 xxxxxxx xxxxxxx 4096 sep 22 14:36 bin
drwxr-xr-x 4 xxxxxxx xxxxxxx 4096 ene 18 12:34 collection1
-rw-r--r-- 1 xxxxxxx xxxxxxx 2473 sep 22 14:36 README.txt
-rw-r--r-- 1 xxxxxxx xxxxxxx 2203 sep 22 14:36 solr.xml
-rw-r--r-- 1 xxxxxxx xxxxxxx  501 sep 22 14:36 zoo.cfg


8) Ahora arrancamos el Tomcat, con lo que se despliega automáticamente el fichero solr.war que habíamos ubicado en la carpeta webapps del Tomcat en el paso 4). Se generará la carpeta webapps/solr.
9) Ahora paramos el Tomcat.
10) Editamos el fichero webapps/solr/WEBINF/web.xml, sustituyendo:

  <!-- People who want to hardcode their "Solr Home" directly into the
       WAR File can set the JNDI property here...
   -->
  <!--
    <env-entry>
       <env-entry-name>solr/home</env-entry-name>
       <env-entry-value>/put/your/solr/home/here</env-entry-value>
       <env-entry-type>java.lang.String</env-entry-type>
    </env-entry>
   -->

por:

  <!-- People who want to hardcode their "Solr Home" directly into the
       WAR File can set the JNDI property here...
   -->

    <env-entry>
       <env-entry-name>solr/home</env-entry-name>
       <env-entry-value>/home/
xxxxxxx/solr</env-entry-value>
       <env-entry-type>java.lang.String</env-entry-type>
    </env-entry>


11) Arrancamos Tomcat y ya podríamos acceder a la página de inicio del portal, http://localhost:8080/solr/admin

Utilización de Solr

Una vez instalado Solr, podemos subir y buscar documentos fácilmente desde Java. Necesitaremos las librerías:

  <dependencies>
      <dependency>
          <groupId>org.apache.solr</groupId>
          <artifactId>solr-common</artifactId>
          <version>1.3.0</version>
      </dependency>
      <dependency>
          <groupId>org.apache.solr</groupId>
          <artifactId>solr-core</artifactId>
          <version>1.4.0</version>
      </dependency>
      <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.7.2</version>
      </dependency>
  </dependencies>


El código de la clase ejemplo sería:

import java.io.IOException;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.client.solrj.impl.XMLResponseParser;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;

public class AppTest {

    /**
     * URL del servidor Solr
     */
    private static final String URL_SOLR = "http://localhost:8080/solr";

    public static void main (String args[]) throws SolrServerException, IOException {
   
        //Conectamos con el servidor Solr
        final CommonsHttpSolrServer serverSolr = new CommonsHttpSolrServer(URL_SOLR);
        serverSolr.setParser(new XMLResponseParser());
       
        //Creamos un par de documentos
        creaDocQuijote(serverSolr);
        creaDocBuscon(serverSolr);
       
        //Buscamos documentos por nombre
        buscaDocNombre(serverSolr, "hidalgo");
       
        //Buscamos documentos por contenido
        buscaDocContenido(serverSolr, "Mancha");
       
        //Borramos todo el contenido del servidor (por aquello de dejarlo limpio y poder repetir las inserciones)
        serverSolr.deleteByQuery("*:*");
    }
   
    private static void creaDocQuijote(final CommonsHttpSolrServer serverSolr) throws SolrServerException, IOException {
       
        final SolrInputDocument doc = new SolrInputDocument();
        doc.addField("id", "000001");
        doc.addField("name", "El ingenioso hidalgo don Quijote.txt");
        doc.addField("text", "En un lugar de la Mancha de cuyo nombre");
        serverSolr.add(doc);
        serverSolr.commit();
    }
   
    private static void creaDocBuscon(final CommonsHttpSolrServer serverSolr) throws SolrServerException, IOException {
       
        final SolrInputDocument doc = new SolrInputDocument();
        doc.addField("id", "000002");
        doc.addField("name", "Buscón.txt");
        doc.addField("text", "Yo, señora, soy de Segovia. Mi padre se llamó Clemente Pablo");
        serverSolr.add(doc);
        serverSolr.commit();
    }
   
    private static void buscaDocNombre(final CommonsHttpSolrServer serverSolr, final String nombre) throws SolrServerException{
       
        final SolrQuery query = new SolrQuery();
        query.setQuery("name:quijote.txt");
        final QueryResponse rsp = serverSolr.query(query);
        final SolrDocumentList docList = rsp.getResults();
        System.out.println("Encontrados "+docList.size()+" documentos con el nombre '"+nombre+"'");
    }
   
    private static void buscaDocContenido(final CommonsHttpSolrServer serverSolr, final String contenido) throws SolrServerException {
       
        final SolrQuery query = new SolrQuery();
        query.setQuery("text:Mancha");
        final QueryResponse rsp = serverSolr.query(query);
        final SolrDocumentList docList = rsp.getResults();
        System.out.println("Encontrados "+docList.size()+" documentos con el contenido '"+contenido+"'");
    }
}


Enlaces de interés

http://stackoverflow.com/questions/10026014/apache-solr-configuration-with-tomcat-6-0
http://www.solrtutorial.com/

sábado, 12 de enero de 2013

Primeros pasos con Apache Velocity

En esta entrada vamos a detallar un ejemplo de uso de Apache Velocity. Esta herramienta nos permite generar fácilmente documentos xml, html, sql, csv, txt, etc.

Apache Velocity renderiza una plantilla con ciertos datos. Las plantillas deberán ser generadas previamente en base al lenguaje VTL (Velocity Template Language).

VTL nos permite generar informes muy grandes con poco esfuerzo.

Supongamos que nos interesa enviar el informe siguiente por correo electrónico:

+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
| 2005       T1         1000 |
| 2005       T2          200 |
| 2005       T3           50 |
| 2005       T4            5 |
+------+------------+--------+


Como primera aproximación montaríamos una plantilla simple, donde las líneas de contenido fijo aparecen tal cual, mientras que en aquellas líneas donde hay conenido variable (año, trimestre y unidades) hemos insertado unas variables  respetando los espacios en blanco que mantienen el encolumnado.

Las diferentes líneas del informe se generan recorriendo los elementos de la lista $listaVentas, cada elemento de la lista se carga en la variable $venta, y cada venta tiene dos atributos: $venta.trim y $venta.unidaddes.

#***************
Plantilla simple
***************#
+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
#foreach($venta in $listaVentas)
| $anno       $venta.trim         $venta.unidades |
#end
+------+------------+--------+


Seguidamente montaríamos el código java, en donde cabe destacar que iniciamos el motor velocity fijando el encoding tanto de la plantilla de entrada como del documento renderizado a generar:

package org.edu.velocity.app;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

public class Test {

    public static void main(String[] args) {

        //Instanciamos el motor velocity
        final VelocityEngine ve = new VelocityEngine();
       
        //Definimos el encoding de entrada y salida
        final Properties props = new Properties();
        props.put("output.encoding","UTF-8");
        props.put("input.encoding","UTF-8");
       
        //Inicializamos el motor velocity con el encoding deseado
        ve.init(props);
       
        //Cargamos la plantilla
        final Template t = ve.getTemplate("informe-simple.vm");
        //final Template t = ve.getTemplate("informe-alineado.vm");
       
        //Preparamos los datos
        final List<Object> listaVentas = new ArrayList<Object>();
        Map<String, String> map = new HashMap<String, String>();
        map.put("trim", "T1");
        map.put("unidades", "1000");
        listaVentas.add(map);
        map = new HashMap<String, String>();
        map.put("trim", "T2");
        map.put("unidades", "200");
        listaVentas.add(map);
        map = new HashMap<String, String>();
        map.put("trim", "T3");
        map.put("unidades", "50");
        listaVentas.add(map);
        map = new HashMap<String, String>();
        map.put("trim", "T4");
        map.put("unidades", "5");
        listaVentas.add(map);
       
        //Creamos el contexto y le metemos los datos
        final VelocityContext context = new VelocityContext();
        context.put("listaVentas", listaVentas);
        context.put("anno", "2005");
       
        //Renderizamos la plantilla
        final StringWriter writer = new StringWriter();
        t.merge( context, writer );
       
        //Visualizamos la plantilla
        System.out.println(writer.toString());

}


Al ejecutar este código tendríamos la siguiente salida:

+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
| 2005       T1         1000 |
| 2005       T2         200 |
| 2005       T3         50 |
| 2005       T4         5 |
+------+------------+--------+


La salida es casi lo que queríamos, pero al variar la longitud de los números de la última columna, tiene un aspecto incorrecto. Vamos a reajustar la plantilla con un control del tamaño de la variable $venta.unidades. Con lo que la plantilla alineada quedaría:

#*****************
Plantilla alineada
*****************#
+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
#foreach($venta in $listaVentas)
#if($venta.unidades.length()==4)
| $anno       $venta.trim         $venta.unidades |
#{elseif}($venta.unidades.length()==3)
| $anno       $venta.trim          $venta.unidades |
#{elseif}($venta.unidades.length()==2)
| $anno       $venta.trim           $venta.unidades |
#{else}
| $anno       $venta.trim            $venta.unidades |
#end
#end
+------+------------+--------+


Si ejecutamos de nuevo el informe tendremos la salida corregida:

+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
| 2005       T1         1000 |
| 2005       T2          200 |
| 2005       T3           50 |
| 2005       T4            5 |
+------+------------+--------+


Librerías.

Para lanzar este ejemplo hemos necesitado las librerías:

velocity-1.7.jar
commons-lang-2.4.jar
commons-collections-3.2.1.jar

Enlaces.

Más información sobre Apache Velocity y VTL en:

http://velocity.apache.org/
http://velocity.apache.org/engine/devel/vtl-reference-guide.html

Conclusiones.

Para generar documentos xml, html, sql, csv y txt, es una herramienta muy potente. La única limitación que le encuentro (sin haberle dedicado mas de una hora al tema), es que si pretendemos generar txt habrá que limitarse a cosas muy simples, dado que en cuanto el documento objetivo es un poco mas complejo la cosa se complica.

No quiero ni pensar qué habría que meter en VTL para generar un informe con varias columnas numéricas que tuviesen que salir alineadas como en el siguiente ejemplo:

+------+-----------+----------+---------+-------+
| Año  | Trimestre | Entradas | Salidas | Stock |
+------+-----------+----------+---------+-------+

| 2005 |     T1    |     1000 |     100 |   900 |
| 2005
|     T2    |      200 |      50 |   150 |
| 2005 |     T3    |       50 |      20 |    30 |
| 2005 |     T4    |        5 |       3 |     2 |
+------+-----------+----------+---------+-------+


La cosa también sería muy compleja si alguien quiere que se generen documentos en txt con justificación completa (es un ejemplo muy rebuscado, me doy cuenta), similares al siguiente ejemplo:

Estimado Juan Español Español.

Nos dirigimos a  vd.  para comunicarle que el
día  17 de  Abril de 2013 a  transferiremos a
la cuenta 0182-0098-XX-XXXXXXXXXX la cantidad
de  1.355,22€ liquidando de ese modo la deuda
pendiente.

En Madrid a 01 de Enero de 2013.

Supongo que las librerías velocity-tools y .

miércoles, 26 de diciembre de 2012

Novedades en Java 7


Java 7 SE presenta novedades a tres niveles: APIs, lenguaje y JVM

1. Novedades en las APIs

1.1) Swing.
  • Se facilita la mezcla de AWT (componentes pesados) con Swing (componentes ligeros).
  • Se posibilitan ventanas con transparencias y con formas no cuadradas.
  • En el componente JColorChooser se habilita la posibilidad de seleccionar todo, saturación y luminusidad (Hue-Saturation-Luminance).
  • Aparece JLayer como decorador para componentes Swing.
  • La apariencia Nimbus se mueve de paquete.
1.2) IO y NIO
  • Gestionar un ZIP como si fuese un file system.
  • Las clases del paquete java.nio.* ofrecen mátodos más intuitivos para la gestión de ficheros y del sistema de archivo.
1.3) Seguridad
  • Soporta TLS 1.1 y TLS 1.2
  • Soporta renegociacion TLS (RFC 5746)
  • Ofrece un mecanismo para rechazar el uso de ciertos algoritmos (los considerados inseguros) en el procesado de rutas de certificación y en el handshaking TLS.
1.4) Concurrencia
  • Se ofrece el framework fork/join para facilitar el trabajo en paralelo (multiporcesador) con un pool de workers.
1.5) Rich Internet Applications (RIA)/Deployment
  • Embedding JNLP File in Applet Tag. Hasta la fecha a la hora de desplegar un applet mediante JNLP, el cliente primero se descargaba el fichero JNLP y luego el jar del app,let con sus dependencias. Ahora podemos incluir el fichero JNLP en el propio JAR del applet así se reduce una llamada y la carga es algo más rápida.
  • Deploying without Codebase. Hasta la fecha en los ficheros JNLP se debía especificar el parámetro Codebase, con Java 7 este parámetro es opcional, si no se indica nada Java Web Start asume que el codebase es relativo a la página web desde la que se lanza la aplicación.
  • Handling Applet Initialization Status with Event Handlers. Cualquier llamada desde JavaScript a un método o a una variable de un applet queda bloqueada hasta que termina el método init() del applet, como además JavaScript no es multihilo, la página web puede parecer congelada durante algunos segundos. Con Java 7 SE, podemos controlar desde JavaScript el estado de carga del applet, si el applet no está cargado podemos registrar los eventos para que se lancen cuando termine de cargarse.
1.6) XML, JAXP, JAXB y JAX-WS
  • Soporta JAXP 1.4.5 (Java API for XML Processing)
  • Soporta JAXB 2.2.3 (Java Architecture for XML Binding)
  • Soporta JAX-WS 2.2.4 (Java API for XML Web Services)
1.7) Internacionalización
  • Soporte de Unicode 6
  • Soporte de para los códigos de monedas ISO 4217
  • Mejoras en el Locale.Category (DISPLAY/FORMAT)
  • Soporte para BCP47 y UTR35 en Locale
   
2. Novedades en el lenguaje

2.1) Podemos manejar literales binarios, hasta ahora sólo se podía con hexadecimales, octales, etc.

        System.out.println("numero "+ 0b1010);

2.2) Se permiten sentencias switch con Strings.

         String dia="lunes";
         switch(dia){
            case "lunes":    System.out.println("Lunes"); break;
            case "martes":     System.out.println("Martes"); break;
            case "miercoles": System.out.println("Miércoles"); break;
            case "jueves":    System.out.println("Jueves"); break;
            case "viernes": System.out.println("Viernes"); break;
            default:        System.out.println("Fin de semana");
        }


2.3) Manejo automático de recursos en try/catch. Se cierran automáticamente archivos, conexiones a bases de datos, etc.

        try(BufferedWriter writer=new BufferedWriter(new FileWriter("/opt/nombreapp/salida/resultado.txt"))) {
               writer.writeln(datos);
        } catch(IOException ex) {
               ex.printStackTrace();
        }


2.4) Captura múltiple de excepciones.

        try {
            System.out.println(10/Integer.parseInt(numero));
        } catch(ArithmeticException | NumberFormatException ex) {
            //manejamos conjuntamente ambas excepciones
        }


2.5) Números con guiones.

        System.out.printf("número: %d%n",1_000);

2.6) Simplificación en el uso de genéricos. Se permiten cosas como:

        List<String> list=new ArrayList<>();

    en vez de:
   
        List<String> list=new ArrayList<String>();

3. Novedades en la JVM

3.1) La JVM soporta lenguajes no java. Java es un lenguaje donde los tipos de datos se verifican en la compilación. Hay otros lenguajes de programación donde los tipos de datos se verifican durante la ejecución, por ejemplo javaScript. Se introduce la nueva instrucción invokedynamic que simplifica y la implementación de compiladores para lenguanes dinámicos en la JVM.

3.2) Garbage-First Collector (o G1 Collector) es una nueva reimplementación del garbage collector orientada a servidores con alto consumo de memoria y multiprocesador. Es interesante su uso en servidores cuando se den una o varias de las siguientes condiciones:
  • Más del 50% de la heap está ocupada con datos activos.
  • Cuando salta el garbage collectior tarda entre 0.5 y 1 seg.
3.3) La JVM HotSpot presenta mejoras de rendimiento:
  • Compilación por capas (Tiered Compilation). Java es "interpretado" en tanto en normalmente ejecuta bytecode y no código máquina, por ello es mas lento. Para solventar esta debilidad, desde la versión 1.3 la JVM HotSpot incorpora JIT         (just-in-time compilation), que compila el bytecode a código máquina antes de ejecutar las clases. Hotspot tiene dos JIT: client JIT y server JIT. El Modo Client del JIT permite arranques más rápidos, pero con menos optimizaciones que el modo Server, que sin embargo arranca más despacio. "Tiered Compilation" tiene lo mejor de los dos compiladores, las optimizaciones del modo Server con la rapidez de arranque del modo Client. Esta mejora puede aplicarse tanto en servidores como en el eclipse.ini.
  • Punteros java comprimidos (Compressed Oops). Los Oop (ordinary object pointer) son los punteros Java a los objetos. Éstos punteros son de 32 o 64 bits según la arquitectura de la máquina. Con 32 bits el tamaño del heap (pila) es menor de 4GB que puede ser poroc para ciertas aplicaciones. Con 64 bits el tamaño del heap es mucho mayor, pero si el aplicativo no necesita realmente ese espacio extra estamos perdiendo memoria. Esta novedad permite usar direcciones de 32 bits aún siendo una arquitectura de 64 bits (una paginación) y ahorrar así memoria. En Java 7 SE, oops es la opción por defecto con JVM de 64-bit si no especificamos un valor para -Xmx o si se especifica un valor inferior a los 32GB.
  • Análisis del alcance de las variables. Otra novedad es el llamado Escape Analysis, mediante esta funcionalidad el compilador JIT de la JVM analiza el alcance de las variables y decide si interesa ubicarlas o no en el heap.
  • NUMA Collector Enhancements. Hoy en día los ordenadores vienen equipados con arquitectura NUMA (Non Uniform Memory Access). Cada rocesador tiene su propia memoria local rápida (como una caché). Java incorpora el NUMA Collector para colocar las variables definidas por cada hilo de un aplicativo en la memoria del procesador que ejecuta ese hilo, así normalmente se aceleran los accesos a memoria y la velocidad de ejecución es mayor.
Notas

Java 7 SE (Standard Edition) se compone de JDK y JRE (como cualquier versión anterior de Java).
  • JRE (Java Runtime Environment). Versión recomendada para la ejecución de aplicaciones Java y applets.
  • JDK (Java Development Kit). Versión recomendada para desarrollar aplicaciones Java y applets. Incorpora el JRE.
Referencias

http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html

viernes, 21 de diciembre de 2012

Introducción a XAdES

En esta entrada vamos a comentar brevemente algunas cuestiones sobre XAdES.

XAdES son las siglas de XML Advanced Electronic Signatures (Firma electrónica avanzada de XML). Define una serie de extensiones a la norma XML-DSig que garantizan una firma electrónica avanzada.

XAdES define siete formatos de firma distintos, cada formato de firma ofrece un nivel de seguridad mayor que el formato anterior:
  • XAdES-BES (Basic Electronic Signature). Primer nivel de seguridad, cumple los requisitos mínimos de la firma electrónica avanzada que son, básicamente: se conoce la identidad del firmante, se garantiza que lo firmado no ha sido alterado y se garantiza que la firma se ha realizado por medios que únicamente controla el firmante.
  • XAdES-EPES (Explicit Policy based Electronic Signature). Segundo nivel de seguridad, añade al nivel anterior información sobre la política de firma. La política de firma es un campo mas de los firmados donde se definen las condiciones generales que el firmante acepta en el momento de realizar la firma.
  • XAdES-T (Timestamp). Tercer nivel de seguridad, añade al nivel anterior un sellado te tiempo. El sellado de tiempo evita que el firmante pueda alegar que cuando se realizó la firma su certificado estaba revocado (cuando, por ejemplo, lo revocó justo unos minutos después de firmar).
  • XAdES-C (Complete). Cuarto nivel de seguridad. El XML de la firma contiene referencias a todos los certificados de la cadena de confianza y referencias a las CRL y/o respuestas OCSP. Tanto los certificados de la cadena de confianza como las CRL/respuestas OCSP son externos a la firma.
  • XAdES-X (eXtended). Quinto nivel de seguridad. Añade sellados de tiempo a las referencias introducidas en el nivel anterior.
  • XAdES-X-L (eXtended Long-term). Sexto nivel de seguridad. Es como XAdES-X, pero ahora el XML contiene internamente los certificados, respuestas OCSP y CRL referenciados.
  • XAdES-A (Archival). Séptimo nivel de seguridad. Las firmas XAdES-X-L pueden presentar problemas de seguridad en los siguientes casos: Si la firma se ve comprometida porque la función hash o los algoritmos de cifrado que la crearon ya no son seguros, o cuando la función hash utilizada por la Autoridad de Sellado de Tiempo ya no sea segura. En éstos casos, se añade un "ArchiveTimeStamp" o sello de tiempo de archivado, a todas las firmas incluidas en el fichero XAdES-X-L (convirtiéndolo, si no lo era ya, en un XAdES-A). Éste nuevo sello de tiempo debe añadirse de forma preventiva ántes de que se de cualquiera de los problemas descritos.
Cuanto mayor es el nivel de seguridad más garantías tendrá la firma y más fácil será verificar su validez en cualquier circunstancia.

En el siguiente gráfico se ve cláramente qué añade cada formato XAdES al formato anterior. Destacar que una firma XMDSIG tendría los componentes ds:SignedInfo, ds:SignatureValue y ds:KeyInfo, por lo que XAdES-BES aporta SignedProperties y UnSignedProperties.

Ubicación de la firma en el XML

Dado un cierto documento xml, podremos aplicar cualquiera de los formatos XAdES antes comentados de cuatro formas distintas sobre un mismo xml.
  • Firma Enveloping
La firma, nodo <ds:signature>, contiene en su interior los datos firmados, que se colocan dentro del nodo <ds:object id="idxxx">, en el nodo <ds:Reference> de la firma que señala el contenido firmado aparecerá algo del tipo URI="#idxxx".

<?xml version="1.0" encoding="UTF-8"?>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo>
    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
    <ds:Reference URI="#idxxx">
      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
      <ds:DigestValue/>
    </ds:Reference>
  </ds:SignedInfo>
  <ds:SignatureValue/>
  <ds:Object id="idxxx">
    <datoslibro>
      <fichalibro Id="libro222">
        <titulo>El ingenioso hidalgo Don Quijote de la Mancha</titulo>
        <autor>Miguel de Cervantes Saavedra</autor>
        <anyo>1605</anyo>
      </fichalibro>
    </datoslibro>
  </ds:Object>
</ds:Signature>

Nota. Si los datos no son XML, no es posible insertarlos directamente dentro de una estructura XML, por lo que se codificarían previamente en Base64.

  • Firma Enveloped (Implicit)
El nodo firmado <datoslibro> contiene en su interior la firma, nodo <ds:signature>, y en el nodo <ds:Reference> de la firma que señala el contenido firmado aparecerá algo del tipo URI="".

<?xml version="1.0" encoding="UTF-8"?>
<datoslibro>
  <fichalibro Id="libro222">
    <titulo>El ingenioso hidalgo Don Quijote de la Mancha</titulo>
    <autor>Miguel de Cervantes Saavedra</autor>
    <anyo>1605</anyo>
  </fichalibro>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
      <ds:Reference URI="">
        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        <ds:DigestValue/>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue/>
  </ds:Signature>
</datoslibro>

Nota. Referenciar en <ds:Reference> una URI vacía ("URI="), implica que la firma aplica a la totalidad del documento original.
  • Firma Detached (Externally Detached)
El fichero xml con la firma está separado del fichero xml con los datos. En el nodo <ds:Reference> del fichero firma se señala el contenido firmado, aparecerá algo del tipo URI="http://servidor/fichero.xml" o algo del tipo URI="http://servidor/fichero.xml#idxxx". En el primer caso se está firmando todo el fichero referenciado por la URI y en el segundo caso únicamente un nodo con ID="idxxx" dentro de ese fichero.

<?xml version="1.0" encoding="UTF-8"?>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo>
    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
    <ds:Reference URI="http://servidor/fichero.xml">
      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
      <ds:DigestValue/>
    </ds:Reference>
  </ds:SignedInfo>
  <ds:SignatureValue/>
</ds:Signature>

Nota. Para que el receptor pueda validar la firma, la URL que referencia el fichero de datos que se ha firmado (http://servidor/fichero.xml) ha de ser accesible al receptor.
  • Firma Mixta (Internally Detached)
La firma, nodo <ds:signature>, va en cualquier posición en un cierto xml y se firma otro nodo de dicho xml. El nodo firmado tendrá un atributo id="idxxx" y en el nodo <ds:Reference> de la firma aparecerá algo del tipo URI="#idxxx".

<?xml version="1.0" encoding="UTF-8"?>
<datoslibro>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
      <ds:Reference URI="#libro222">
        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        <ds:DigestValue/>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue/>
  </ds:Signature>
  <fichalibro Id="libro222">
    <titulo>El ingenioso hidalgo Don Quijote de la Mancha</titulo>
    <autor>Miguel de Cervantes Saavedra</autor>
    <anyo>1605</anyo>
  </fichalibro>
</datoslibro>

Firmas comparadas

Vamos a ver ahora un ejemplo de cada tipo de firma, empezando en XAdES-BES y terminando en XAdES-XL. En cada ejemplo destacamos en negrita la finalidad de cada nodo y destacamos en rojo los nodos nuevos o que cambian respecto al nivel XAdES anterior.

XAdES-BES.

<?xml version="1.0" encoding="UTF-8"?>
<documento>
    <enifile:contenido Id="I-CONT-0123456789">DATOS A FIRMAR EN BASE64</enifile:contenido>
    <ds:Signature xmlns:etsi="http://uri.etsi.org/01903/v1.3.2#"
        Id="Signature801100">
        <ds:SignedInfo Id="Signature-SignedInfo248625">
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
            <ds:Reference Id="SignedPropertiesID49278" Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature801100-SignedProperties758537">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LAS SignedProperties EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#Certificate1868714">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LA CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference Id="Reference-ID-595057" URI="#I-CONT-0123456789">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LOS DATOS A FIRMAR EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue Id="SignatureValue630921">VALOR DE LA FIRMA EN BASE 64</ds:SignatureValue>
        <ds:KeyInfo Id="Certificate1868714">
            <ds:X509Data>
                <ds:X509Certificate>CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64</ds:X509Certificate>
            </ds:X509Data>
            <ds:KeyValue>
                <ds:RSAKeyValue>
                    <ds:Modulus>MODULO DE LA CLAVE RSA EN BASE 64</ds:Modulus>
                    <ds:Exponent>EXPONENTE DE LA CLAVE RSA EN BASE 64</ds:Exponent>
                </ds:RSAKeyValue>
            </ds:KeyValue>
        </ds:KeyInfo>
        <ds:Object Id="Signature801100-Object282070">
            <etsi:QualifyingProperties Target="#Signature801100">
                <etsi:SignedProperties Id="Signature801100-SignedProperties758537">
                    <etsi:SignedSignatureProperties>
                        <etsi:SigningTime>FECHA Y HORA DE LA FIRMA</etsi:SigningTime>
                        <etsi:SigningCertificate>
                            <etsi:Cert>
                                <etsi:CertDigest>
                                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                    <ds:DigestValue>UESvWZbj+klE48bfOWis4yDlOQE=
                                    </ds:DigestValue>
                                </etsi:CertDigest>
                                <etsi:IssuerSerial>
                                    <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO FIRMANTE</ds:X509IssuerName>
                                    <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO FIRMANTE</ds:X509SerialNumber>
                                </etsi:IssuerSerial>
                            </etsi:Cert>
                        </etsi:SigningCertificate>
                    </etsi:SignedSignatureProperties>
                    <etsi:SignedDataObjectProperties>
                        <etsi:DataObjectFormat ObjectReference="#Reference-ID-595057">
                            <etsi:Description>DESCRIPCION DEL OBJETO FIRMADO</etsi:Description>
                        </etsi:DataObjectFormat>
                    </etsi:SignedDataObjectProperties>
                </etsi:SignedProperties>
            </etsi:QualifyingProperties>
        </ds:Object>
    </ds:Signature>
</documento>


XAdES-EPES. La diferencia con XAdES-BES es que se incluye <etsi:SignaturePolicyIdentifier> con la política de firma usada.

<?xml version="1.0" encoding="UTF-8"?>
<documento>
    <enifile:contenido Id="I-CONT-0123456789">DATOS A FIRMAR EN BASE64</enifile:contenido>
    <ds:Signature xmlns:etsi="http://uri.etsi.org/01903/v1.3.2#"
        Id="Signature848615">
        <ds:SignedInfo Id="Signature-SignedInfo293839">
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
            <ds:Reference Id="SignedPropertiesID228478" Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature848615-SignedProperties458805">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LAS SignedProperties EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#Certificate1353906">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LA CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference Id="Reference-ID-372892" URI="#I-CONT-0123456789">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LOS DATOS A FIRMAR EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue Id="SignatureValue630921">VALOR DE LA FIRMA EN BASE 64</ds:SignatureValue>
        <ds:KeyInfo Id="Certificate1353906">
            <ds:X509Data>
                <ds:X509Certificate>CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64</ds:X509Certificate>
            </ds:X509Data>
            <ds:KeyValue>
                <ds:RSAKeyValue>
                    <ds:Modulus>MODULO DE LA CLAVE RSA EN BASE 64</ds:Modulus>
                    <ds:Exponent>EXPONENTE DE LA CLAVE RSA EN BASE 64</ds:Exponent>
                </ds:RSAKeyValue>
            </ds:KeyValue>
        </ds:KeyInfo>
        <ds:Object Id="Signature848615-Object70279">
            <etsi:QualifyingProperties Target="#Signature848615">
                <etsi:SignedProperties Id="Signature848615-SignedProperties458805">
                    <etsi:SignedSignatureProperties>
                        <etsi:SigningTime>FECHA Y HORA DE LA FIRMA</etsi:SigningTime>
                        <etsi:SigningCertificate>
                            <etsi:Cert>
                                <etsi:CertDigest>
                                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                    <ds:DigestValue>UESvWZbj+klE48bfOWis4yDlOQE=
                                    </ds:DigestValue>
                                </etsi:CertDigest>
                                <etsi:IssuerSerial>
                                    <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO FIRMANTE</ds:X509IssuerName>
                                    <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO FIRMANTE</ds:X509SerialNumber>
                                </etsi:IssuerSerial>
                            </etsi:Cert>
                        </etsi:SigningCertificate>
                        <etsi:SignaturePolicyIdentifier>
                            <etsi:SignaturePolicyImplied>INFORMACION DE LA POLITICA DE FIRMA</etsi:SignaturePolicyImplied>
                        </etsi:SignaturePolicyIdentifier>

                    </etsi:SignedSignatureProperties>
                    <etsi:SignedDataObjectProperties>
                        <etsi:DataObjectFormat ObjectReference="#Reference-ID-372892">
                            <etsi:Description>DESCRIPCION DEL OBJETO FIRMADO</etsi:Description>
                        </etsi:DataObjectFormat>
                    </etsi:SignedDataObjectProperties>
                </etsi:SignedProperties>
            </etsi:QualifyingProperties>
        </ds:Object>
    </ds:Signature>
</documento>


XAdES-T. La diferencia con XAdES-BES o con XAdES-EPES es que se añade un <etsi:EncapsulatedTimeStamp> dentro de las <etsi:UnsignedSignatureProperties>, con la fecha/hora de la firma. Así el firmante no puede repudiar la firma, alegando por ejemplo que su certificado fué revocado en la fecha de la firma.

<?xml version="1.0" encoding="UTF-8"?>
<documento>
    <enifile:contenido Id="I-CONT-0123456789">DATOS A FIRMAR EN BASE64</enifile:contenido>
    <ds:Signature xmlns:etsi="http://uri.etsi.org/01903/v1.3.2#"
        Id="Signature754596">
        <ds:SignedInfo Id="Signature-SignedInfo1043088">
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
            <ds:Reference Id="SignedPropertiesID368251" Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature754596-SignedProperties419098">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LAS SignedProperties EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#Certificate1697788">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LA CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference Id="Reference-ID-415022" URI="#I-CONT-0123456789">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LOS DATOS A FIRMAR EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue Id="SignatureValue630921">VALOR DE LA FIRMA EN BASE 64</ds:SignatureValue>
        <ds:KeyInfo Id="Certificate1697788">
            <ds:X509Data>
                <ds:X509Certificate>CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64</ds:X509Certificate>
            </ds:X509Data>
            <ds:KeyValue>
                <ds:RSAKeyValue>
                    <ds:Modulus>MODULO DE LA CLAVE RSA EN BASE 64</ds:Modulus>
                    <ds:Exponent>EXPONENTE DE LA CLAVE RSA EN BASE 64</ds:Exponent>
                </ds:RSAKeyValue>
            </ds:KeyValue>
        </ds:KeyInfo>
        <ds:Object Id="Signature754596-Object328709">
            <etsi:QualifyingProperties Target="#Signature754596">
                <etsi:SignedProperties Id="Signature754596-SignedProperties419098">
                    <etsi:SignedSignatureProperties>
                        <etsi:SigningTime>FECHA Y HORA DE LA FIRMA</etsi:SigningTime>
                        <etsi:SigningCertificate>
                            <etsi:Cert>
                                <etsi:CertDigest>
                                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                    <ds:DigestValue>UESvWZbj+klE48bfOWis4yDlOQE=
                                    </ds:DigestValue>
                                </etsi:CertDigest>
                                <etsi:IssuerSerial>
                                    <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO FIRMANTE</ds:X509IssuerName>
                                    <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO FIRMANTE</ds:X509SerialNumber>
                                </etsi:IssuerSerial>
                            </etsi:Cert>
                        </etsi:SigningCertificate>
                        <etsi:SignaturePolicyIdentifier>
                            <etsi:SignaturePolicyImplied>INFORMACION DE LA POLITICA DE FIRMA</etsi:SignaturePolicyImplied>
                        </etsi:SignaturePolicyIdentifier>
                    </etsi:SignedSignatureProperties>
                    <etsi:SignedDataObjectProperties>
                        <etsi:DataObjectFormat ObjectReference="#Reference-ID-415022">
                            <etsi:Description>DESCRIPCION DEL OBJETO FIRMADO</etsi:Description>
                        </etsi:DataObjectFormat>
                    </etsi:SignedDataObjectProperties>
                </etsi:SignedProperties>
                <etsi:UnsignedProperties Id="Signature754596-UnsignedProperties41621">
                    <etsi:UnsignedSignatureProperties>
                        <etsi:SignatureTimeStamp Id="SelloTiempo896970">
                            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
                            <etsi:EncapsulatedTimeStamp Id="SelloTiempo-Token639298">SELLO DE TIEMPO EN BASE 64</etsi:EncapsulatedTimeStamp>
                        </etsi:SignatureTimeStamp>
                    </etsi:UnsignedSignatureProperties>
                </etsi:UnsignedProperties>

            </etsi:QualifyingProperties>
        </ds:Object>
    </ds:Signature>
</documento>


XAdES-C. La diferencia con XAdES-T es que se añaden <etsi:CompleteCertificateRefs> y <etsi:CompleteRevocationRefs> dentro de <etsi:UnsignedProperties>. En <etsi:CompleteCertificateRefs> aparecen referenciados (referencias a ficheros externos "*.cer" que acompañan al XML) todos los certificados de la cadena de confianza. En <etsi:CompleteRevocationRefs> aparecen referenciadas (referencias externas a ficheros "*.ors" que acompañan al XML) las respuestas OCSP sobre el estado del certificado en el momento de la firma (en éste caso el emisor de los certificados no responde con CRL's).

<?xml version="1.0" encoding="UTF-8"?>
<documento>
    <enifile:contenido Id="I-CONT-0123456789">DATOS A FIRMAR EN BASE64</enifile:contenido>
    <ds:Signature xmlns:etsi="http://uri.etsi.org/01903/v1.3.2#"
        Id="Signature233908">
        <ds:SignedInfo Id="Signature-SignedInfo217186">
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
            <ds:Reference Id="SignedPropertiesID759589" Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature233908-SignedProperties66892">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LAS SignedProperties EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#Certificate1706205">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LA CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference Id="Reference-ID-378304" URI="#I-CONT-0123456789">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LOS DATOS A FIRMAR EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue Id="SignatureValue630921">VALOR DE LA FIRMA EN BASE 64</ds:SignatureValue>
        <ds:KeyInfo Id="Certificate1706205">
            <ds:X509Data>
                <ds:X509Certificate>CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64</ds:X509Certificate>
            </ds:X509Data>
            <ds:KeyValue>
                <ds:RSAKeyValue>
                    <ds:Modulus>MODULO DE LA CLAVE RSA EN BASE 64</ds:Modulus>
                    <ds:Exponent>EXPONENTE DE LA CLAVE RSA EN BASE 64</ds:Exponent>
                </ds:RSAKeyValue>
            </ds:KeyValue>
        </ds:KeyInfo>
        <ds:Object Id="Signature233908-Object557197">
            <etsi:QualifyingProperties Target="#Signature233908">
                <etsi:SignedProperties Id="Signature233908-SignedProperties66892">
                    <etsi:SignedSignatureProperties>
                        <etsi:SigningTime>FECHA Y HORA DE LA FIRMA</etsi:SigningTime>
                        <etsi:SigningCertificate>
                            <etsi:Cert>
                                <etsi:CertDigest>
                                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                    <ds:DigestValue>UESvWZbj+klE48bfOWis4yDlOQE=
                                    </ds:DigestValue>
                                </etsi:CertDigest>
                                <etsi:IssuerSerial>
                                    <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO FIRMANTE</ds:X509IssuerName>
                                    <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO FIRMANTE</ds:X509SerialNumber>
                                </etsi:IssuerSerial>
                            </etsi:Cert>
                        </etsi:SigningCertificate>
                        <etsi:SignaturePolicyIdentifier>
                            <etsi:SignaturePolicyImplied>INFORMACION DE LA POLITICA DE FIRMA</etsi:SignaturePolicyImplied>
                        </etsi:SignaturePolicyIdentifier>
                    </etsi:SignedSignatureProperties>
                    <etsi:SignedDataObjectProperties>
                        <etsi:DataObjectFormat ObjectReference="#Reference-ID-378304">
                            <etsi:Description>DESCRIPCION DEL OBJETO FIRMADO</etsi:Description>
                        </etsi:DataObjectFormat>
                    </etsi:SignedDataObjectProperties>
                </etsi:SignedProperties>
                <etsi:UnsignedProperties Id="Signature233908-UnsignedProperties850646">
                    <etsi:UnsignedSignatureProperties>
                        <etsi:SignatureTimeStamp Id="SelloTiempo903560">
                            <ds:CanonicalizationMethod
                                Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
                            <etsi:EncapsulatedTimeStamp Id="SelloTiempo-Token673096">SELLO DE TIEMPO EN BASE 64</etsi:EncapsulatedTimeStamp>
                        </etsi:SignatureTimeStamp>
                        <etsi:CompleteCertificateRefs Id="CompleteCertificateRefs678300">
                            <etsi:CertRefs>
                                <etsi:Cert URI="cert-51d4e435.cer">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                                <etsi:Cert URI="cert-51e269b9.cer">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                                <etsi:Cert URI="cert-af48ca99.cer">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                                <etsi:Cert URI="cert-dfcf6bea.cer">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                            </etsi:CertRefs>
                        </etsi:CompleteCertificateRefs>
                        <etsi:CompleteRevocationRefs Id="CompleteRevocationRefs813975">
                            <etsi:OCSPRefs>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="ocsp-b38ce045.ors">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="ocsp-955e683.ors">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="ocsp-9c33e31b.ors">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="ocsp-40d5e753.ors">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                            </etsi:OCSPRefs>
                        </etsi:CompleteRevocationRefs>

                    </etsi:UnsignedSignatureProperties>
                </etsi:UnsignedProperties>
            </etsi:QualifyingProperties>
        </ds:Object>
    </ds:Signature>
</documento>


XAdES-X. La diferencia con XAdES-C está en que se añade un segundo Timestamp, ésta vez aplicado a los datos <etsi:CompleteCertificateRefs> y <etsi:CompleteRevocationRefs> para evitar que se vea comprometida la cadena de certificados en el futuro.

<?xml version="1.0" encoding="UTF-8"?>
<documento>
    <enifile:contenido Id="I-CONT-0123456789">DATOS A FIRMAR EN BASE64</enifile:contenido>
    <ds:Signature xmlns:etsi="http://uri.etsi.org/01903/v1.3.2#"
        Id="Signature75894">
        <ds:SignedInfo Id="Signature-SignedInfo719420">
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
            <ds:Reference Id="SignedPropertiesID74902" Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature75894-SignedProperties122672">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LAS SignedProperties EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#Certificate1800244">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LA CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference Id="Reference-ID-697504" URI="#I-CONT-0123456789">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LOS DATOS A FIRMAR EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue Id="SignatureValue630921">VALOR DE LA FIRMA EN BASE 64</ds:SignatureValue>
        <ds:KeyInfo Id="Certificate1800244">
            <ds:X509Data>
                <ds:X509Certificate>CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64</ds:X509Certificate>
            </ds:X509Data>
            <ds:KeyValue>
                <ds:RSAKeyValue>
                    <ds:Modulus>MODULO DE LA CLAVE RSA EN BASE 64</ds:Modulus>
                    <ds:Exponent>EXPONENTE DE LA CLAVE RSA EN BASE 64</ds:Exponent>
                </ds:RSAKeyValue>
            </ds:KeyValue>
        </ds:KeyInfo>
        <ds:Object Id="Signature75894-Object383841">
            <etsi:QualifyingProperties Target="#Signature75894">
                <etsi:SignedProperties Id="Signature75894-SignedProperties122672">
                    <etsi:SignedSignatureProperties>
                        <etsi:SigningTime>FECHA Y HORA DE LA FIRMA</etsi:SigningTime>
                        <etsi:SigningCertificate>
                            <etsi:Cert>
                                <etsi:CertDigest>
                                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                    <ds:DigestValue>UESvWZbj+klE48bfOWis4yDlOQE=
                                    </ds:DigestValue>
                                </etsi:CertDigest>
                                <etsi:IssuerSerial>
                                    <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO FIRMANTE</ds:X509IssuerName>
                                    <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO FIRMANTE</ds:X509SerialNumber>
                                </etsi:IssuerSerial>
                            </etsi:Cert>
                        </etsi:SigningCertificate>
                        <etsi:SignaturePolicyIdentifier>
                            <etsi:SignaturePolicyImplied>INFORMACION DE LA POLITICA DE FIRMA</etsi:SignaturePolicyImplied>
                        </etsi:SignaturePolicyIdentifier>
                    </etsi:SignedSignatureProperties>
                    <etsi:SignedDataObjectProperties>
                        <etsi:DataObjectFormat ObjectReference="#Reference-ID-697504">
                            <etsi:Description>DESCRIPCION DEL OBJETO FIRMADO</etsi:Description>
                        </etsi:DataObjectFormat>
                    </etsi:SignedDataObjectProperties>
                </etsi:SignedProperties>
                <etsi:UnsignedProperties Id="Signature75894-UnsignedProperties209264">
                    <etsi:UnsignedSignatureProperties>
                        <etsi:SignatureTimeStamp Id="SelloTiempo217564">
                            <ds:CanonicalizationMethod
                                Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
                            <etsi:EncapsulatedTimeStamp Id="SelloTiempo-Token641659">SELLO DE TIEMPO EN BASE 64</etsi:EncapsulatedTimeStamp>
                        </etsi:SignatureTimeStamp>
                        <etsi:CompleteCertificateRefs Id="CompleteCertificateRefs116069">
                            <etsi:CertRefs>
                                <etsi:Cert URI="cert-51d4e435.cer">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                                <etsi:Cert URI="cert-51e269b9.cer">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                                <etsi:Cert URI="cert-af48ca99.cer">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                                <etsi:Cert URI="cert-dfcf6bea.cer">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                            </etsi:CertRefs>
                        </etsi:CompleteCertificateRefs>
                        <etsi:CompleteRevocationRefs Id="CompleteRevocationRefs821214">
                            <etsi:OCSPRefs>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="ocsp-210ae699.ors">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="ocsp-8ede475.ors">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="ocsp-7c96e708.ors">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="ocsp-6c35ecac.ors">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                            </etsi:OCSPRefs>
                        </etsi:CompleteRevocationRefs>
                        <etsi:SigAndRefsTimeStamp Id="SelloTiempo481184">
                            <ds:CanonicalizationMethod
                                Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
                            <etsi:EncapsulatedTimeStamp>SELLO DE TIEMPO PARA LA CADENA DE CERTIFICADOS EN BASE 64</etsi:EncapsulatedTimeStamp>
                        </etsi:SigAndRefsTimeStamp>

                    </etsi:UnsignedSignatureProperties>
                </etsi:UnsignedProperties>
            </etsi:QualifyingProperties>
        </ds:Object>
    </ds:Signature>
</documento>


XAdES-X-L. la diferencia con XAdES-X radica en que ahora tanto los certificados como las respuestas OCSP (en el ejemplo no se usa CRL), van incluídas en el XML, en los nodos <etsi:CertificateValues> y <etsi:RevocationValues> de <etsi:UnsignedSignatureProperties>. Con ello se garantiza que se podrá realizar la validación de la firma en cualquier momento, incluso si los servidores OCSP ya no estuviesen disponibles.

<?xml version="1.0" encoding="UTF-8"?>
<documento>
    <enifile:contenido Id="I-CONT-0123456789">DATOS A FIRMAR EN BASE64</enifile:contenido>
    <ds:Signature xmlns:etsi="http://uri.etsi.org/01903/v1.3.2#"
        Id="Signature840357">
        <ds:SignedInfo Id="Signature-SignedInfo757927">
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
            <ds:Reference Id="SignedPropertiesID858972" Type="http://uri.etsi.org/01903#SignedProperties" URI="#Signature840357-SignedProperties56116">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LAS SignedProperties EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#Certificate1308388">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LA CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
            <ds:Reference Id="Reference-ID-254481" URI="#I-CONT-0123456789">
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                <ds:DigestValue>HUELLA DE LOS DATOS A FIRMAR EN BASE 64 (ELEMENTO REFERENCIADO)</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue Id="SignatureValue630921">VALOR DE LA FIRMA EN BASE 64</ds:SignatureValue>
        <ds:KeyInfo Id="Certificate1308388">
            <ds:X509Data>
                <ds:X509Certificate>CLAVE PUBLICA DEL CERTIFICADO FIRMANTE EN BASE 64</ds:X509Certificate>
            </ds:X509Data>
            <ds:KeyValue>
                <ds:RSAKeyValue>
                    <ds:Modulus>MODULO DE LA CLAVE RSA EN BASE 64</ds:Modulus>
                    <ds:Exponent>EXPONENTE DE LA CLAVE RSA EN BASE 64</ds:Exponent>
                </ds:RSAKeyValue>
            </ds:KeyValue>
        </ds:KeyInfo>
        <ds:Object Id="Signature840357-Object731972">
            <etsi:QualifyingProperties Target="#Signature840357">
                <etsi:SignedProperties Id="Signature840357-SignedProperties56116">
                    <etsi:SignedSignatureProperties>
                        <etsi:SigningTime>FECHA Y HORA DE LA FIRMA</etsi:SigningTime>
                        <etsi:SigningCertificate>
                            <etsi:Cert>
                                <etsi:CertDigest>
                                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                    <ds:DigestValue>UESvWZbj+klE48bfOWis4yDlOQE=
                                    </ds:DigestValue>
                                </etsi:CertDigest>
                                <etsi:IssuerSerial>
                                    <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO FIRMANTE</ds:X509IssuerName>
                                    <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO FIRMANTE</ds:X509SerialNumber>
                                </etsi:IssuerSerial>
                            </etsi:Cert>
                        </etsi:SigningCertificate>
                        <etsi:SignaturePolicyIdentifier>
                            <etsi:SignaturePolicyImplied>INFORMACION DE LA POLITICA DE FIRMA</etsi:SignaturePolicyImplied>
                        </etsi:SignaturePolicyIdentifier>
                    </etsi:SignedSignatureProperties>
                    <etsi:SignedDataObjectProperties>
                        <etsi:DataObjectFormat ObjectReference="#Reference-ID-254481">
                            <etsi:Description>DESCRIPCION DEL OBJETO FIRMADO</etsi:Description>
                        </etsi:DataObjectFormat>
                    </etsi:SignedDataObjectProperties>
                </etsi:SignedProperties>
                <etsi:UnsignedProperties Id="Signature840357-UnsignedProperties774105">
                    <etsi:UnsignedSignatureProperties>
                        <etsi:SignatureTimeStamp Id="SelloTiempo278440">
                            <ds:CanonicalizationMethod
                                Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
                            <etsi:EncapsulatedTimeStamp Id="SelloTiempo-Token124272">SELLO DE TIEMPO EN BASE 64</etsi:EncapsulatedTimeStamp>
                        </etsi:SignatureTimeStamp>
                        <etsi:CompleteCertificateRefs Id="CompleteCertificateRefs891280">
                            <etsi:CertRefs>
                                <etsi:Cert URI="#CertPath222992">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                                <etsi:Cert URI="#CertPath523050">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                                <etsi:Cert URI="#CertPath888969">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                                <etsi:Cert URI="#CertPath986853">
                                    <etsi:CertDigest>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:CertDigest>
                                    <etsi:IssuerSerial>
                                        <ds:X509IssuerName>NOMBRE DEL EMISOR DEL CERTIFICADO</ds:X509IssuerName>
                                        <ds:X509SerialNumber>NUMERO DE SERIE DEL CERTIFICADO</ds:X509SerialNumber>
                                    </etsi:IssuerSerial>
                                </etsi:Cert>
                            </etsi:CertRefs>
                        </etsi:CompleteCertificateRefs>
                        <etsi:CompleteRevocationRefs Id="CompleteRevocationRefs409336">
                            <etsi:OCSPRefs>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="#OCSP270">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="#OCSP870468">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="#OCSP745695">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                                <etsi:OCSPRef>
                                    <etsi:OCSPIdentifier URI="#OCSP884900">
                                        <etsi:ResponderID>
                                            <etsi:ByName>NOMBRE DEL SERVIDOR OCSP</etsi:ByName>
                                        </etsi:ResponderID>
                                        <etsi:ProducedAt>FECHA EN QUE SE LANZO LA CONSULTA AL SERVER OCSP</etsi:ProducedAt>
                                    </etsi:OCSPIdentifier>
                                    <etsi:DigestAlgAndValue>
                                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                                        <ds:DigestValue>HUELLA DE LA RESPUESTA OCSP</ds:DigestValue>
                                    </etsi:DigestAlgAndValue>
                                </etsi:OCSPRef>
                            </etsi:OCSPRefs>
                        </etsi:CompleteRevocationRefs>
                        <etsi:SigAndRefsTimeStamp Id="SelloTiempo979579">
                            <ds:CanonicalizationMethod
                                Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
                            <etsi:EncapsulatedTimeStamp>SELLO DE TIEMPO PARA LA CADENA DE CERTIFICADOS EN BASE 64</etsi:EncapsulatedTimeStamp>
                        </etsi:SigAndRefsTimeStamp>
                        <etsi:CertificateValues Id="CertificateValues27705">
                            <etsi:EncapsulatedX509Certificate Id="CertPath890794">CERTIFICADO EN BASE 64</etsi:EncapsulatedX509Certificate>
                            <etsi:EncapsulatedX509Certificate Id="CertPath222992">CERTIFICADO EN BASE 64</etsi:EncapsulatedX509Certificate>
                            <etsi:EncapsulatedX509Certificate Id="CertPath523050">CERTIFICADO EN BASE 64</etsi:EncapsulatedX509Certificate>
                            <etsi:EncapsulatedX509Certificate Id="CertPath888969">CERTIFICADO EN BASE 64</etsi:EncapsulatedX509Certificate>
                            <etsi:EncapsulatedX509Certificate Id="CertPath986853">CERTIFICADO EN BASE 64</etsi:EncapsulatedX509Certificate>
                        </etsi:CertificateValues>
                        <etsi:RevocationValues Id="RevocationValues275593">
                            <etsi:OCSPValues>
                                <etsi:EncapsulatedOCSPValue Id="OCSP270">RESPUESTA OCSP EN BASE 64</etsi:EncapsulatedOCSPValue>
                                <etsi:EncapsulatedOCSPValue Id="OCSP870468">RESPUESTA OCSP EN BASE 64</etsi:EncapsulatedOCSPValue>
                                <etsi:EncapsulatedOCSPValue Id="OCSP745695">RESPUESTA OCSP EN BASE 64</etsi:EncapsulatedOCSPValue>
                                <etsi:EncapsulatedOCSPValue Id="OCSP884900">RESPUESTA OCSP EN BASE 64</etsi:EncapsulatedOCSPValue>
                            </etsi:OCSPValues>
                        </etsi:RevocationValues>

                    </etsi:UnsignedSignatureProperties>
                </etsi:UnsignedProperties>
            </etsi:QualifyingProperties>
        </ds:Object>
    </ds:Signature>
</documento>


Enlaces de interés.

http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel
http://oficinavirtual.mityc.es/componentes/MITyCLibXADES/
http://www.w3.org/TR/XAdES/

Un saludo