Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Cómo implementar un componente procesador de consultas XUL

Imagen:traduccion-pendiente.png Esta página está traduciéndose a partir del artículo How_to implement a custom XUL query processor component, razón por la cual puede haber algunos errores sintácticos o partes sin traducir. Puedes colaborar continuando con la traducción


El servicio XUL apoya el uso de plantillas para crear un bloque de contenidos a partir de una consulta a una fuente de datos. La Guia de Plantillas XUL presenta una gran fuente de información detallada acerca del uso de las plantillas XUL. El servicio XUL proporciona procesadores de consulta de plantillas para RDF, XML y SQL (mozStorage). Este sistema de plantillas también da soporte a la creación de procesadores de consultas personalizadas. Los procesadores de consultas personalizadas son componentes XPCOM que deben implementar la interfaz nsIXULTemplateQueryProcessor y seguir algunos de los criterios que indican cuándo se deben registrar los mismos.

En este ejemplo, crearemos un sencillo componente XPCOM en JavaScript. Dicho componente mantendrá una pequeña selección de objetos de JavaScript en su fuente de datos. En la práctica, se usaría una fuente propia de datos personalizada.

A continuación presentamos un ejemplo del posible aspecto que podría tener nuestro servicio de XUL al utilizar un procesador de consultas personalizado:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="https://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <grid>
        <columns>
            <column flex="1"/>
            <column flex="3"/>
            <column flex="2"/>
            <column flex="1"/>
        </columns>

        <rows datasources="dummy" ref="." querytype="simpledata">
            <template>
                <row uri="?">
                    <label value="?name"/>
                    <label value="?age"/>
                    <label value="?hair"/>
                    <label value="?eye"/>
                </row>
            </template>
        </rows>
    </grid>
</window>

Algunas cosas a tener en cuenta. En realidad no estamos utilizando las fuentes de datos en nuestro componente de ejemplo, por lo que lo configuraremos con un valor no válido. Un hilo vacío también valdría. El tipo de consulta es importante. Se usa para crear un caso de nuestro objeto XPCOM. La contracción de la identidad de nuestro componente XPCOM debería tener la forma de "@mozilla.org/xul/xul-query-processor;1?name=xxx", donde las xxx representan el tipo de consulta utilizado en el bloque de plantillas XUL. A continuación mostramos nuestro ejemplo de procesador de consultas XPCOM de JavaScript:

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");


// basic wrapper for nsIXULTemplateResult
function TemplateResult(aData) {
  this._data = aData;
  // just make a random number for the id
  this._id = Math.random(100000).toString();
}

TemplateResult.prototype = {
  QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIXULTemplateResult]),

  // private storage
  _data: null,

  // right now our results are flat lists, so no containing/recursion take place
  isContainer: false,
  isEmpty: true,
  mayProcessChildren: false,
  resource: null,
  type: "simple-item",

  get id() {
    return this._id;
  },

  // return the value of that bound variable such as ?name
  getBindingFor: function(aVar) {
    // strip off the ? from the beginning of the name
    var name = aVar.toString().slice(1);
    return this._data[name];
  },

  // return an object instead of a string for convenient comparison purposes
  // or null to say just use string value
  getBindingObjectFor: function(aVar) {
    return null;
  },

  // called when a rule matches this item.
  ruleMatched: function(aQuery, aRuleNode) { },

  // the output for a result has been removed and the result is no longer being used by the builder
  hasBeenRemoved: function() { }
};


// basic wrapper for nsISimpleEnumerator
function TemplateResultSet(aArrayOfData) {
  this._index = 0;
  this._array = aArrayOfData;
}

TemplateResultSet.prototype = {
  QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISimpleEnumerator]),

  hasMoreElements: function() {
    return this._index < this._array.length;
  },

  getNext: function() {
    return new TemplateResult(this._array[this._index++]);
  }
};


// The query processor class - implements nsIXULTemplateQueryProcessor
function TemplateQueryProcessor() {
  // our basic list of data
  this._data = [
                {name: "mark", age: 36, hair: "brown", eye: "brown"},
                {name: "bill", age: 25, hair: "red", eye: "black"},
                {name: "joe", age: 15, hair: "blond", eye: "blue"},
                {name: "jimmy", age: 65, hair: "gray", eye: "dull"}
               ];
}

TemplateQueryProcessor.prototype = {
  QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIXULTemplateQueryProcessor]),
  classDescription: "Sample XUL Template Query Processor",
  classID: Components.ID("{282cc4ea-a49c-44fc-81f4-1f03cbb7825f}"),
  contractID: "@mozilla.org/xul/xul-query-processor;1?name=simpledata",

  getDatasource: function(aDataSources, aRootNode, aIsTrusted, aBuilder, aShouldDelayBuilding) {
    // TODO: parse the aDataSources variable
    // for now, ignore everything and let's just signal that we have data
    return this._data;
  },

  initializeForBuilding: function(aDatasource, aBuilder, aRootNode) {
    // perform any initialization that can be delayed until the content builder
    // is ready for us to start
  },

  done: function() {
    // called when the builder is destroyed to clean up state
  },

  compileQuery: function(aBuilder, aQuery, aRefVariable, aMemberVariable) {
    // outputs a query object.
    // eventually we should read the <query> to create filters
    return this._data;
  },

  generateResults: function(aDatasource, aRef, aQuery) {
    // preform any query and pass the data to the result set
    return new TemplateResultSet(this._data);
  },

  addBinding: function(aRuleNode, aVar, aRef, aExpr) {
    // add a variable binding for a particular rule, which we aren't using yet
  },

  translateRef: function(aDatasource, aRefstring) {
    // if we return null, everything stops
    return new TemplateResult(null);
  },

  compareResults: function(aLeft, aRight, aVar) {
    // -1 less, 0 ==, +1 greater
    if (aLeft < aRight) {
      return -1;
    }
    else if (aLeft > aRight) {
      return  1;
    }
    else {
      return 0;
    }
  }
};


var components = [TemplateQueryProcessor];

function NSGetModule(compMgr, fileSpec) {
  return XPCOMUtils.generateModule(components);
}

Nuestro ejemplo de procesador de consultas es muy fácil. Notas aclaratorias:

  • Estamos usando el getBindingFor en vez del getBindingObjectFor para simplificar así el código. La variable introducida en el getBindingFor todavía conserva las “?” por lo que debéis aseguraros de introducirla de forma correcta.
  • No se usarán cualquiera de los elementos <query/> o <rule/> en el bloque de plantillas de XUL. Se podrá hacer uso de éstas para apoyar el filtrado de fuentes de datos.
  • No estamos manejando fuentes de datos, sino que en su lugar, estamos introduciendo a mano el componente. Se podría ampliar fácilmente este ejemplo para manejar varias fuentes de datos a través de la comprobación del valor de las mismas en el getDatasource y en el initializeForBuilding.
  • No se usarán cualquiera de los elementos <query/> o <rule/> en el bloque de plantillas de XUL. Se podrá hacer uso de éstas para apoyar el filtrado de fuentes de datos.

Etiquetas y colaboradores del documento

 Colaboradores en esta página: Nukeador, Kaltya, Mgjbot
 Última actualización por: Nukeador,