# CirrusXML

## Qué ?

CirrusXML es una biblioteca realmente simple sin dependencias de npm, Nodejs o navegador, es un parser, editor y xml to JSON converter.

## Por qué ?

Manta\_xml se desarrolló porque existen javascript engines mucho más simples que v8, SpiderMonkey o Chakra, los motores js más simples pueden 'entender' javascript pero no tenían acceso a bindings de C/C++, módulos de nodo o Npm para aprovechar las librerías existentes.

## Cómo ?

### Instalación

La librería agregará una variable global llamada CirrusXML que expone las funciones xml2JSON, xmlParser y XMLDocument.

### Uso

#### Crear un nuevo documento XML.

CirrusXML básicamente utiliza una estructura de árbol de Nodos , por lo que para crear la representación interna de un documento XML, lo único que se debe hacer es instanciar un objeto XMLDocument con los atributos para el nodo raíz y luego agregar nuevos nodos a la estructura.

Ejemplo:

```javascript
var XMLDocument = CirrusXML.XMLDocument,
    document    = new XMLDocument({nodeName: "body", attrs: {id: "main", class: "body"}}),
    node        = document.find({nodeName: "body"})[0],
    pNode       = new Node({nodeName: "p", attrs: {class: "bold"}, _text: "Hello world"});

node.addChild(pNode);

document.toXML(true);
/*
  <?xml version="1.0" encoding="UTF-8"?>
  <body id="main" class="body">
    <p class="bold">
      Hello World
    </p>
  </body>
*/

document.toJSON()
/*
  {
    "body":{
        "_attrs":{
          "id":"main",
          "class":"body"
        },
        "p":{
          "_attrs":{
              "class":"bold"
          },
          "_text": "Hello "World"
        }
    }
  }
*/
```

#### Parseando y Editando un documento XML.

Es posible parsear un documento XML, encontrar y editar algunos de sus nodos y luego obtener una cadena JSON o XML del documento  en su estado actual.

Revisa el  objeto Nodo para ver cómo cambiar los atributos, nodeName, texto o valores de CData para un nodo en particular.

**Ejemplo de parseo y edición:**

```javascript
var xmlParser = CirrusXML.xmlParser,
    document  = xmlParser("<node id='23'>inner text</node>"),
    node      = document.find({attrs: {id: '23'}})[0],
    newChild  = new Node({nodeName: "child", attrs: {id: "2"}});

node.setAttr("id", "24");
node.setAttr("name", "Manta");
node.setText("New inner text");
node.addChild(newChild);

document.toXML();
// <?xml version="1.0" encoding="UTF-8"?><node id="24" name="Manta">New inner text<child id="2"></child></node>

// or a formatted xml
document.toXML(true);
/**
* <?xml version="1.0" encoding="UTF-8"?>
* <node id="24" name="Manta">
*   New inner text
*   <child id="2">
*   </child>
* </node>
*/
```

#### Convertir un XML a JSON.

La función xml2JSON tomará cualquier cadena xml e intentará parsearla y convertirla en un objeto JSON equivalente.

```javascript
var xml2JSON = CirrusXML.xml2JSON;

json = xml2JSON("<node id='23'>inner text</node>");
// {node: {attrs: {id: '23'}, _text: 'inner text'}  }
```

### Búsquedas.

Para buscar en el documento xml hay un método 'find' que puede recibir un query object o una función callback para recorrer el árbol xml y encontrar nodos que coincidan con los parámetros.

#### **Resultado de la consulta**

En ambos casos, el resultado es el mismo, un Array con objetos que representan los nodos xml coincidentes, estos objetos pueden ser el objeto Node en sí mismo o un objeto JSON que representa el nodo como este:

```javascript
[{nodeName: 'node1', attrs: {id: '1'}, _text: "some text"}, {nodeName: 'node2', attrs: {id: '2', name: 'second node'}}]
```

El JSON que representa cada nodo siempre tendrá las atributos 'nodeName' y 'attrs'  y tendrá las atributos '\_text' o '\_cdata' si el nodo actual envuelve alguna expresión de texto o cdata.

Si tu intención es editar los atributos de los nodos, el texto, el CData, agregar o quitar nodos secundarios, necesita acceso directo al objeto Node y por ello el método find **por defecto** retorna un Array de nodos.

&#x20;**Búsqueda por query object:**&#x20;

La búsqueda con un query object es bastante simple,  al método find se le llama con parámetro que indica el atributo por el cual deseas buscar y un valor con el que puede coincidir, puede ser un valor estándar (cadena, int, bool, etc.) o un literal regex .

**Sintaxis**

```javascript
var xmlParser = CirrusXML.xmlParser,
    document  = xmlParser(".... some xml ...");

document.find({attrs: {some_attribute: 'value to match'}});
```

&#x20;**Ejemplos** :

```javascript
// Busca nodos con un atributo id igual a 1234, algo como <bill id='1234'>
results = document.find({attrs: {id: '1234'}})

// Busca nodos con un atributo id igual a 1234, algo como <bill id='1234'>
// Pero retorna un JSON.
results = document.find({attrs: {id: '1234'}}, true)

// Encuentra todos los nodos de tipo bill, <bill id='123' total='20000'>
results = document.find({nodeName: 'bill'});

// Encuentra todos los nodos que tengan un atributo name que comience con 'ever' => <direction name='evergreen avenue' />
results = document.find({attrs: {name: /^ever/}});

// Encuentra todos los nodos cuyo texto interno incluya la palabra "world" => <line id='12'>Hello world</line>
results = document.find({_text: /world/});

// Encuentra todos los nodos cuyo atributo nombre es igual a "line" y  su texto interno incluye la palabra "world" => <node1 name='line'>without world</node1><node2 name='line'>something else</node2>
results = document.find({_text: /mundo/, attrs: {name: 'line'}});
```

#### &#x20;**Búsqueda con una función callback:**&#x20;

Si necesitas más control sobre la búsqueda o realizar algunas operaciones, puedes pasar un callback al método 'find' en lugar de un query object, el callback recibirá un objeto Node y debería devolver un valor booleano para indicar si el nodo es un es match en la búsqueda.

&#x20;**ejemplos** :

```javascript
// Busca nodos con un atributo id igual a 1234, algo como <bill id='1234'>
results = document.find(function(node) {
    return(node.attrs.id && node.attrs.id === '1234');
});

// Busca todos los nodos de tipo bill, <bill id='123' total='20000'>
results = document.find(function(node) {
    return(node.nodeName === 'factura');
});

// Busca todos los nodos para quienes el valor del atributo name comience con 'ever' => <direction name='evergreen avenue'/>
results = document.find(function(node) {
    return(node.attrs.name && node.attrs.name.match(/ever/));
});
```

#### El Objeto de Node

El Objeto de Node es un objeto simple que contiene sus propios datos, una referencia a su nodo paterno y una lista de nodos hijos; para crear un nuevo nodo, simplemente debe crearse una instancia del objeto Node con un JSON que serán sus atributos.

&#x20;**lista de métodos** :

* setAttr
* getAttr
* setText
* getText
* setCData
* getCData
* addChild
* deleteChild

&#x20;**Ejemplos de uso** :

```javascript
var node = new Node({id: "node", class: "inner"});

node.setAttr("name", "Hello world");
console.log(node.getAttr("name"));

node.setText("Hello this is an inner text");
node.setCData("<p>some weird html</p>");

var child = new Node({id: "node2", class: "inner"});

node.addChild(child);
```
