Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare una empresa de Scribd logo
Rails y XML como herramienta de Integración obra publicada por javier ramirez como ‘Atribución-No Comercial-Licenciar Igual 2.5’ de Creative Commons [email_address]
¿por qué xml? ¿por qué rails? ¿cómo? integración vía REST
estándar de facto, universal legible y flexible posibilidad de representar jerarquías ¿por qué xml?
iteradores cómodos consola para pruebas métodos y librerías de xml en la distribución conversión automática ¿por qué rails?
método to_xml builder XMLSimple REXML ¿cómo? generación  de xml interpretación de xml
<?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> <topic> <parent-id></parent-id> <title>The First Topic</title> <author-name>David</author-name> <id type=&quot;integer&quot;>1</id> <approved type=&quot;boolean&quot;>false</approved> <replies-count type=&quot;integer&quot;>0</replies-count> <bonus-time type=&quot;datetime&quot;>2000-01-01T08:28:00+12:00</bonus-time> <written-on type=&quot;datetime&quot;>2003-07-16T09:28:00+1200</written-on> <content>Have a nice day</content> <author-email-address>david@loudthinking.com</author-email-address> <last-read type=&quot;date&quot;>2004-04-15</last-read>  </topic>  xml básico instruct root attribute text element
xml desde cualquier modelo, con includes de primer nivel xml desde cualquier hash, incluso anidadas xml desde arrays si todos sus elementos responden a to_xml método to_xml..
no soporta atributos sustitución de _ por - :root, :except, :only, :skip_instruct, :include, :indent ..método to_xml.
permite generar cualquier xml de forma sencilla, con elementos, atributos, namespaces, contenido mixto y cualquier anidamiento permite lanzar eventos al estilo SAX builder..
xm.html do   # <html>  xm.head do   # <head>  xm.title(&quot;History&quot;)   # <title>History</title>  end  # </head>  xm.body do   # <body>  xm.comment! &quot;HI&quot;   # <!-- HI -->  xm.h1(&quot;Header&quot;)   # <h1>Header</h1>  xm.p(&quot;paragraph&quot;)   # <p>paragraph</p>  end   # </body>  end   # </html>  ..builder..
Builder::XmlMarkup.new :target :indent :margin instruct! (tag=:xml,attrs{}) <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?>  ..builder..
comment! xm.comment! 'test'  <!– test --> declare! xm.declare! :DOCTYPE :article :PUBLIC &quot;//OASIS/DTD&quot;  <!DOCTYPE article PUBLIC &quot;//OASIS/DTD&quot;> cdata! xm.cdata! 'test'  <![CDATA[test]]>   text! para texto no escapado puede usarse xm << 'test & >' ..builder..
method_missing xm.evento 'conferencia rails'  <evento>conferencia rails</evento> xm.evento 'conferencia',:id=>1,:year=>'2006' <evento year=&quot;2006&quot; id=&quot;1&quot;>conferencia</evento> xm.RAILS :evento, 'conferencia', :year=>'2006' <RAILS:evento year=&quot;2006&quot;>conferencia</RAILS:evento> tag! ..builder..
contenido mixto <p class=&quot;weblink&quot;>visita la web<a href= &quot;http://www.conferenciarails.org&quot;> conferencia rails</a></p> xm.p('visita la web ',:class=>'weblink') do xm.a 'conferenciarails', :href=>'http://www.conferenciarails.org' end xm.p(:class=>'weblink') do xm.text! 'visita la web' xm.a 'conferencia rails', :href=>'http://www.conferenciarails.org' end ..builder..
en vistas rxml, accesible mediante el objeto xml para usar partials en el caller render partial=>'partial_name', :locals=>{parent_xml=>xml} en el partial xml = parent_xml unless !parent_xml ..builder.
mapeo de xml a arrays/hashes ruby de forma sencilla depende de rexml. rexml viene con ruby y xmlsimple con rails es una adaptación de la librería perl XML::Simple xmlsimple..
XmlSimple.xml_in nil|xml_string|filename|IO, args XmlSimple.xml_out (hash) ..xmlsimple..
<opt> <person firstname=&quot;Joe&quot; lastname=&quot;Smith&quot;>  <email>joe@smith.com</email>  <email>jsmith@yahoo.com</email> </person> <person firstname=&quot;Bob&quot; lastname=&quot;Smith&quot;>  <email>bob@smith.com</email> </person> </opt>  { 'person' => [  { 'email' => [ 'joe@smith.com', 'jsmith@yahoo.com' ], 'firstname' => 'Joe', 'lastname' => 'Smith' },  { 'email' => ['bob@smith.com'], 'firstname' => 'Bob', 'lastname' => 'Smith' }  ] }  ..xmlsimple..
ForceArray ( true |false) | ([lista]) <opt> <person><email>joe@smith.com</email></person> </opt>  XmlSimple.xml_in (xml,'ForceArray'=>true) {'opt‘=>[{'person' =>[{ 'email' => [ 'joe@smith.com']}]}]} XmlSimple.xml_in (xml,'ForceArray'=>false) { ' opt'=> {'person' =>{ 'email' =>'joe@smith.com'}}} ..xmlsimple..
KeyAttr [lista] | {elemento=>lista} <opt> <user login=&quot;grep&quot; fullname=&quot;Gary R Epstein&quot; /> <user login=&quot;stty&quot; fullname=&quot;Simon T Tyson&quot; /> </opt>  xml_in (xml, { 'KeyAttr' => ‘login' }) { 'user' => {  'stty' => { 'fullname' => 'Simon T Tyson' },  'grep' => { 'fullname' => 'Gary R Epstein' } } }  xml_in (xml, { 'KeyAttr' => { 'user' => &quot;+login&quot; }}) { 'user' => {  'stty' => { 'fullname' => 'Simon T Tyson', 'login' => 'stty' }, 'grep' => { 'fullname' => 'Gary R Epstein', 'login' => 'grep' } } }  ..xmlsimple..
xml =%q( <opt> <x>text1</x> <y a=&quot;2&quot;>text2</y> </opt>) { 'x' => 'text1',  'y' => { 'a' => '2', 'content' => 'text2' }  ForceContent XmlSimple.xml_in(xml, { 'ForceContent' => true })  { 'x' => { 'content' => 'text1' },      'y' => { 'a' => '2', 'content' => 'text2' } } ContentKey XmlSimple.xml_in(xml, { 'ContentKey' => 'text' })  { 'x' => 'text1',  'y' => { 'a' => '2', ‘text' => 'text2' } ..xmlsimple..
KeepRoot (true| false ) RootName (xml_out) def:opt OutputFile (xml_out) SupressEmpty (true|nil|’’) def:[] Variables (name=>value) ${} ..xmlsimple..
XmlDeclaration (true|string) KeyToSymbol (true| false ) NoEscape (true| false ) NormaliseSpace ( 0 |1|2) 0: sin normalizar 1: normaliza sólo hash keys 2: normaliza todo  ..xmlsimple..
Si queremos usar varias veces los mismos parámetros de inicialización, podemos crear una instancia con las opciones deseadas my_xml = XmlSimple.new (ForceArray=>true, KeepRoot=>true) my_xml.xml_in %q(<root><H1>test</H1></root>) ..xmlsimple..
Si recibimos un request con content-type = “application/xml” se usa xmlsimple dejando una hash en params[:root_name] Para otros content-types ActionController::Base.param_parsers [Mime::Type.lookup( 'application/xml+soap' )] = :xml_simple ..xmlsimple.
parser xml completo.incluído en ruby soporte de xpath modelos soportados tree / dom  stream / sax (push) stream / sax2 (push) stream / stax (pull) rexml..
modelo DOM, con estilo ruby java: for (Enumeration e=parent.getChildren(); e.hasMoreElements(); )  { Element child = (Element)e.nextElement();  // Do something with child } rexml: parent.each_child { |child| # Do something with child }  ..rexml..
document.root element.each element.elements element.attributes ..rexml..
element element.name devuelve el tag element.next_element element.previous_element element.next_sibling element.previous_sibling element.root_node ..rexml..
elements accesible por index, desde 1 opcionalmente por index,nombre accesible por nombre. devuelve  el primero con ese tag each_element_with_attribute each_element_with_text elements.to_a  ..rexml..
attributes accesible por nombre each {|key,value|} to_a ['key=value',…] ..rexml..
xpath REXML::XPath.first (element,expr) REXML::XPath.each (element,expr) REXML::Xpath.match (element,expr) ..rexml..
xpath desde elements elements.each (xpath_expr) elements[xpath_expr] elements.to_a (xpath_expr) ..rexml..
ejemplos con xpath doc.elements.each('/inventory/section/item') doc.elements.each('//item[@stock='18']) doc.elements[&quot;//price[text()='14.50']/..&quot;] ..rexml..
textos accesible mediante element.text siempre en utf-8 se sustituyen las entidades tanto XML como definidas en el DTD ..rexml..
creación / modificación de nodos el.add_element 'item' el.add_element 'item', {'stock'=>'18'} el.text = '4.95' el.add_text '4,95' el.delete_element el.delete_attribute el['stock'] = '18' ..rexml..
streaming parsers lanzan eventos mientras se lee el xml más rápidos que DOM y con menos consumo de memoria. útiles en documentos grandes requieren 'máquina de estados' ..rexml..
rexml stream parser ~ sax Document.parse_stream(source, listener) métodos REXML::StreamListener tag_start / tag_end text / cdata comment entity / entitydecl doctype / doctype_end attlistdecl / elementdecl instruction / notationdecl / xmldecl ..rexml..
sax2 parser es como el streaming parser, pero con la posibilidad de filtrar los eventos que se lanzan permite escuchar eventos vía listeners o mediante procs ..rexml..
proceso de eventos via procs require 'rexml/sax2parser'  parser = REXML::SAX2Parser.new( File.new( 'documentation.xml' ) ) parser.listen( :characters ) {|text| puts text } parser.parse  parser.listen( :characters, %w{ changelog todo } ) {|text| puts text }  parser.listen(%w{ item } ) {|uri,localname,qname,attributes| puts qname}  ..rexml..
proceso de eventos via listeners listener = MySAX2Listener.new parser.listen( listener ) item_listener = MySAX2Listener.new parser.listen (%w{item}, item_listener) parser.parse  podemos procesar eventos mediante procs y listeners de  forma combinada. Los listeners se procesan más rápidamente, pero necesitamos crear un objeto con los métodos apropiados ..rexml..
pull parser ~ stax en lugar de escuchar eventos, se piden items y luego se comprueba su tipo requiere mantener máquina de estados, pero el código es más legible ..rexml..
el pull parser en rexml está todavía en estado experimental parser = PullParser.new( &quot;<a>text<b att='val'/>txet</a>&quot; )  while parser.has_next?  res = parser.next  puts res[1]['att'] if res.start_tag? and res[0] == 'b'  raise res[1] if res.error? end ..rexml.
los servicios web son demasiado complejos para muchos casos cuando se realizan consultas, se envía menos información que la que se recibe. podemos exponer la misma api al usuario final y a la máquina REST:  representational state transfer..
modelo rails = rest resource un recurso se identifica con una uri www.example.com/item/200776 permite cachear las peticiones ya servidas ..rest..
rest propone separar las operaciones con resources en tres partes verbo nombre content-type a diferencia de XML-RPC, el conjunto de operaciones (verbos) es limitado y hay en su lugar muchos nombres (recursos) diferentes ..rest..
rest efectúa las operaciones CRUD mediante los verbos HTTP PUT/ GET/ POST/ DELETE el content-type puede ser cualquiera, incluso diferente para la entrada y la salida (ej: url=>xml) ..rest..
if request.post?  if params[:id]  # update  else # no ID  # create elsif request.get?  # mostrar el modelo en xml elsif request.delete?  # delete end  ..rest.. para distinguir la operación a realizar
def show_item @item = Item.find(params[:id]) respond_to do |accepts| accepts.html accepts.xml {render :xml=>@item.to_xml} end end ..rest.. para poder servir al cliente diferentes content-types según su cabecera Accept:
delegando en rails para la recepción de parámetros via querystring o xml de forma transparente (usando xmlsimple por debajo) y utilizando el mecanismo respond_to, podemos servir aplicaciones rest en diferentes formatos con el mínimo esfuerzo ..rest.
las librerías proporcionadas en la distribución estándar de ruby on rails permiten la interpretación y la generación de xml de una forma rápida, sencilla y limpia las facilidades de prueba directa en la consola, agilizan el desarrollo como resultado, usar rails mejora la productividad cuando tratamos xml conclusión
Rails y XML como herramienta de Integración obra publicada por javier ramirez como ‘Atribución-No Comercial-Licenciar Igual 2.5’ de Creative Commons [email_address]

Más contenido relacionado

Similar a Xml On Rails

PHP
PHPPHP
Datos En La Web - Clase 1
Datos En La Web - Clase 1Datos En La Web - Clase 1
Datos En La Web - Clase 1
Sebastian Galiano
 
Xml
XmlXml
Xml
XmlXml
XML en .NET
XML en .NETXML en .NET
XML en .NET
brobelo
 
Javascript
JavascriptJavascript
Clase xml as3
Clase xml as3Clase xml as3
Clase xml as3
Andres Garcia
 
Cont clase de lenguaje IV
Cont clase de lenguaje IVCont clase de lenguaje IV
Cont clase de lenguaje IV
guestc906c2
 
Intro a ruby
Intro a rubyIntro a ruby
Intro a ruby
Velmuz Buzz
 
Codigos HTML Continuación
Codigos HTML ContinuaciónCodigos HTML Continuación
Codigos HTML Continuación
guestc906c2
 
Curso de Django | Django Course
Curso de Django | Django CourseCurso de Django | Django Course
Curso de Django | Django Course
aleperalta
 
Html Y Javascript
Html Y JavascriptHtml Y Javascript
Html Y Javascript
oswchavez
 
Html Y Javascript
Html Y JavascriptHtml Y Javascript
Html Y Javascript
oswchavez
 
Taller I Coreis Python 10112009
Taller I Coreis Python 10112009Taller I Coreis Python 10112009
Taller I Coreis Python 10112009
Carlos Cardenas Fernandez
 
Introducción xml
Introducción xmlIntroducción xml
Introducción xml
Philippe-Jean Bunau-Varilla
 
Trabajo final programacion
Trabajo final programacionTrabajo final programacion
Trabajo final programacion
markos1992
 
Qué es xhtml
Qué es xhtmlQué es xhtml
Qué es xhtml
Capacitacion web
 
Diapositivas del resumen y ejercicios(finalizada)
Diapositivas del resumen y ejercicios(finalizada)Diapositivas del resumen y ejercicios(finalizada)
Diapositivas del resumen y ejercicios(finalizada)
guest6a4fee
 
Diapositivas del resumen y ejercicios(finalizada) (1)
Diapositivas del resumen y ejercicios(finalizada) (1)Diapositivas del resumen y ejercicios(finalizada) (1)
Diapositivas del resumen y ejercicios(finalizada) (1)
guestc229aba9
 
Presentación de programación (conceptos y ejercicios)
Presentación de programación (conceptos y ejercicios)Presentación de programación (conceptos y ejercicios)
Presentación de programación (conceptos y ejercicios)
guest6a4fee
 

Similar a Xml On Rails (20)

PHP
PHPPHP
PHP
 
Datos En La Web - Clase 1
Datos En La Web - Clase 1Datos En La Web - Clase 1
Datos En La Web - Clase 1
 
Xml
XmlXml
Xml
 
Xml
XmlXml
Xml
 
XML en .NET
XML en .NETXML en .NET
XML en .NET
 
Javascript
JavascriptJavascript
Javascript
 
Clase xml as3
Clase xml as3Clase xml as3
Clase xml as3
 
Cont clase de lenguaje IV
Cont clase de lenguaje IVCont clase de lenguaje IV
Cont clase de lenguaje IV
 
Intro a ruby
Intro a rubyIntro a ruby
Intro a ruby
 
Codigos HTML Continuación
Codigos HTML ContinuaciónCodigos HTML Continuación
Codigos HTML Continuación
 
Curso de Django | Django Course
Curso de Django | Django CourseCurso de Django | Django Course
Curso de Django | Django Course
 
Html Y Javascript
Html Y JavascriptHtml Y Javascript
Html Y Javascript
 
Html Y Javascript
Html Y JavascriptHtml Y Javascript
Html Y Javascript
 
Taller I Coreis Python 10112009
Taller I Coreis Python 10112009Taller I Coreis Python 10112009
Taller I Coreis Python 10112009
 
Introducción xml
Introducción xmlIntroducción xml
Introducción xml
 
Trabajo final programacion
Trabajo final programacionTrabajo final programacion
Trabajo final programacion
 
Qué es xhtml
Qué es xhtmlQué es xhtml
Qué es xhtml
 
Diapositivas del resumen y ejercicios(finalizada)
Diapositivas del resumen y ejercicios(finalizada)Diapositivas del resumen y ejercicios(finalizada)
Diapositivas del resumen y ejercicios(finalizada)
 
Diapositivas del resumen y ejercicios(finalizada) (1)
Diapositivas del resumen y ejercicios(finalizada) (1)Diapositivas del resumen y ejercicios(finalizada) (1)
Diapositivas del resumen y ejercicios(finalizada) (1)
 
Presentación de programación (conceptos y ejercicios)
Presentación de programación (conceptos y ejercicios)Presentación de programación (conceptos y ejercicios)
Presentación de programación (conceptos y ejercicios)
 

Más de javier ramirez

Cómo hemos implementado semántica de "Exactly Once" en nuestra base de datos ...
Cómo hemos implementado semántica de "Exactly Once" en nuestra base de datos ...Cómo hemos implementado semántica de "Exactly Once" en nuestra base de datos ...
Cómo hemos implementado semántica de "Exactly Once" en nuestra base de datos ...
javier ramirez
 
How We Added Replication to QuestDB - JonTheBeach
How We Added Replication to QuestDB - JonTheBeachHow We Added Replication to QuestDB - JonTheBeach
How We Added Replication to QuestDB - JonTheBeach
javier ramirez
 
The Building Blocks of QuestDB, a Time Series Database
The Building Blocks of QuestDB, a Time Series DatabaseThe Building Blocks of QuestDB, a Time Series Database
The Building Blocks of QuestDB, a Time Series Database
javier ramirez
 
¿Se puede vivir del open source? T3chfest
¿Se puede vivir del open source? T3chfest¿Se puede vivir del open source? T3chfest
¿Se puede vivir del open source? T3chfest
javier ramirez
 
QuestDB: The building blocks of a fast open-source time-series database
QuestDB: The building blocks of a fast open-source time-series databaseQuestDB: The building blocks of a fast open-source time-series database
QuestDB: The building blocks of a fast open-source time-series database
javier ramirez
 
Como creamos QuestDB Cloud, un SaaS basado en Kubernetes alrededor de QuestDB...
Como creamos QuestDB Cloud, un SaaS basado en Kubernetes alrededor de QuestDB...Como creamos QuestDB Cloud, un SaaS basado en Kubernetes alrededor de QuestDB...
Como creamos QuestDB Cloud, un SaaS basado en Kubernetes alrededor de QuestDB...
javier ramirez
 
Ingesting Over Four Million Rows Per Second With QuestDB Timeseries Database ...
Ingesting Over Four Million Rows Per Second With QuestDB Timeseries Database ...Ingesting Over Four Million Rows Per Second With QuestDB Timeseries Database ...
Ingesting Over Four Million Rows Per Second With QuestDB Timeseries Database ...
javier ramirez
 
Deduplicating and analysing time-series data with Apache Beam and QuestDB
Deduplicating and analysing time-series data with Apache Beam and QuestDBDeduplicating and analysing time-series data with Apache Beam and QuestDB
Deduplicating and analysing time-series data with Apache Beam and QuestDB
javier ramirez
 
Your Database Cannot Do this (well)
Your Database Cannot Do this (well)Your Database Cannot Do this (well)
Your Database Cannot Do this (well)
javier ramirez
 
Your Timestamps Deserve Better than a Generic Database
Your Timestamps Deserve Better than a Generic DatabaseYour Timestamps Deserve Better than a Generic Database
Your Timestamps Deserve Better than a Generic Database
javier ramirez
 
Cómo se diseña una base de datos que pueda ingerir más de cuatro millones de ...
Cómo se diseña una base de datos que pueda ingerir más de cuatro millones de ...Cómo se diseña una base de datos que pueda ingerir más de cuatro millones de ...
Cómo se diseña una base de datos que pueda ingerir más de cuatro millones de ...
javier ramirez
 
QuestDB-Community-Call-20220728
QuestDB-Community-Call-20220728QuestDB-Community-Call-20220728
QuestDB-Community-Call-20220728
javier ramirez
 
Processing and analysing streaming data with Python. Pycon Italy 2022
Processing and analysing streaming  data with Python. Pycon Italy 2022Processing and analysing streaming  data with Python. Pycon Italy 2022
Processing and analysing streaming data with Python. Pycon Italy 2022
javier ramirez
 
QuestDB: ingesting a million time series per second on a single instance. Big...
QuestDB: ingesting a million time series per second on a single instance. Big...QuestDB: ingesting a million time series per second on a single instance. Big...
QuestDB: ingesting a million time series per second on a single instance. Big...
javier ramirez
 
Servicios e infraestructura de AWS y la próxima región en Aragón
Servicios e infraestructura de AWS y la próxima región en AragónServicios e infraestructura de AWS y la próxima región en Aragón
Servicios e infraestructura de AWS y la próxima región en Aragón
javier ramirez
 
Primeros pasos en desarrollo serverless
Primeros pasos en desarrollo serverlessPrimeros pasos en desarrollo serverless
Primeros pasos en desarrollo serverless
javier ramirez
 
How AWS is reinventing the cloud
How AWS is reinventing the cloudHow AWS is reinventing the cloud
How AWS is reinventing the cloud
javier ramirez
 
Analitica de datos en tiempo real con Apache Flink y Apache BEAM
Analitica de datos en tiempo real con Apache Flink y Apache BEAMAnalitica de datos en tiempo real con Apache Flink y Apache BEAM
Analitica de datos en tiempo real con Apache Flink y Apache BEAM
javier ramirez
 
Getting started with streaming analytics
Getting started with streaming analyticsGetting started with streaming analytics
Getting started with streaming analytics
javier ramirez
 
Getting started with streaming analytics: Setting up a pipeline
Getting started with streaming analytics: Setting up a pipelineGetting started with streaming analytics: Setting up a pipeline
Getting started with streaming analytics: Setting up a pipeline
javier ramirez
 

Más de javier ramirez (20)

Cómo hemos implementado semántica de "Exactly Once" en nuestra base de datos ...
Cómo hemos implementado semántica de "Exactly Once" en nuestra base de datos ...Cómo hemos implementado semántica de "Exactly Once" en nuestra base de datos ...
Cómo hemos implementado semántica de "Exactly Once" en nuestra base de datos ...
 
How We Added Replication to QuestDB - JonTheBeach
How We Added Replication to QuestDB - JonTheBeachHow We Added Replication to QuestDB - JonTheBeach
How We Added Replication to QuestDB - JonTheBeach
 
The Building Blocks of QuestDB, a Time Series Database
The Building Blocks of QuestDB, a Time Series DatabaseThe Building Blocks of QuestDB, a Time Series Database
The Building Blocks of QuestDB, a Time Series Database
 
¿Se puede vivir del open source? T3chfest
¿Se puede vivir del open source? T3chfest¿Se puede vivir del open source? T3chfest
¿Se puede vivir del open source? T3chfest
 
QuestDB: The building blocks of a fast open-source time-series database
QuestDB: The building blocks of a fast open-source time-series databaseQuestDB: The building blocks of a fast open-source time-series database
QuestDB: The building blocks of a fast open-source time-series database
 
Como creamos QuestDB Cloud, un SaaS basado en Kubernetes alrededor de QuestDB...
Como creamos QuestDB Cloud, un SaaS basado en Kubernetes alrededor de QuestDB...Como creamos QuestDB Cloud, un SaaS basado en Kubernetes alrededor de QuestDB...
Como creamos QuestDB Cloud, un SaaS basado en Kubernetes alrededor de QuestDB...
 
Ingesting Over Four Million Rows Per Second With QuestDB Timeseries Database ...
Ingesting Over Four Million Rows Per Second With QuestDB Timeseries Database ...Ingesting Over Four Million Rows Per Second With QuestDB Timeseries Database ...
Ingesting Over Four Million Rows Per Second With QuestDB Timeseries Database ...
 
Deduplicating and analysing time-series data with Apache Beam and QuestDB
Deduplicating and analysing time-series data with Apache Beam and QuestDBDeduplicating and analysing time-series data with Apache Beam and QuestDB
Deduplicating and analysing time-series data with Apache Beam and QuestDB
 
Your Database Cannot Do this (well)
Your Database Cannot Do this (well)Your Database Cannot Do this (well)
Your Database Cannot Do this (well)
 
Your Timestamps Deserve Better than a Generic Database
Your Timestamps Deserve Better than a Generic DatabaseYour Timestamps Deserve Better than a Generic Database
Your Timestamps Deserve Better than a Generic Database
 
Cómo se diseña una base de datos que pueda ingerir más de cuatro millones de ...
Cómo se diseña una base de datos que pueda ingerir más de cuatro millones de ...Cómo se diseña una base de datos que pueda ingerir más de cuatro millones de ...
Cómo se diseña una base de datos que pueda ingerir más de cuatro millones de ...
 
QuestDB-Community-Call-20220728
QuestDB-Community-Call-20220728QuestDB-Community-Call-20220728
QuestDB-Community-Call-20220728
 
Processing and analysing streaming data with Python. Pycon Italy 2022
Processing and analysing streaming  data with Python. Pycon Italy 2022Processing and analysing streaming  data with Python. Pycon Italy 2022
Processing and analysing streaming data with Python. Pycon Italy 2022
 
QuestDB: ingesting a million time series per second on a single instance. Big...
QuestDB: ingesting a million time series per second on a single instance. Big...QuestDB: ingesting a million time series per second on a single instance. Big...
QuestDB: ingesting a million time series per second on a single instance. Big...
 
Servicios e infraestructura de AWS y la próxima región en Aragón
Servicios e infraestructura de AWS y la próxima región en AragónServicios e infraestructura de AWS y la próxima región en Aragón
Servicios e infraestructura de AWS y la próxima región en Aragón
 
Primeros pasos en desarrollo serverless
Primeros pasos en desarrollo serverlessPrimeros pasos en desarrollo serverless
Primeros pasos en desarrollo serverless
 
How AWS is reinventing the cloud
How AWS is reinventing the cloudHow AWS is reinventing the cloud
How AWS is reinventing the cloud
 
Analitica de datos en tiempo real con Apache Flink y Apache BEAM
Analitica de datos en tiempo real con Apache Flink y Apache BEAMAnalitica de datos en tiempo real con Apache Flink y Apache BEAM
Analitica de datos en tiempo real con Apache Flink y Apache BEAM
 
Getting started with streaming analytics
Getting started with streaming analyticsGetting started with streaming analytics
Getting started with streaming analytics
 
Getting started with streaming analytics: Setting up a pipeline
Getting started with streaming analytics: Setting up a pipelineGetting started with streaming analytics: Setting up a pipeline
Getting started with streaming analytics: Setting up a pipeline
 

Último

Bifurcaciones edición 18 - eHealth (salud digital)
Bifurcaciones edición 18 - eHealth (salud digital)Bifurcaciones edición 18 - eHealth (salud digital)
Bifurcaciones edición 18 - eHealth (salud digital)
Juan Jesús Velasco Rivera
 
Tecnología Educativa en el marco formación universitaria
Tecnología Educativa en el marco formación universitariaTecnología Educativa en el marco formación universitaria
Tecnología Educativa en el marco formación universitaria
sofiaespinolanutrici
 
"Los 10 Beneficios Clave de Contratar un Asistente Virtual" pdf
"Los 10 Beneficios Clave de Contratar un Asistente Virtual" pdf"Los 10 Beneficios Clave de Contratar un Asistente Virtual" pdf
"Los 10 Beneficios Clave de Contratar un Asistente Virtual" pdf
tiendadigitalboutique
 
tecnosaramineiropalaciosegundoperiodo.docx
tecnosaramineiropalaciosegundoperiodo.docxtecnosaramineiropalaciosegundoperiodo.docx
tecnosaramineiropalaciosegundoperiodo.docx
SaraMineiropalacio
 
Conceptos básicos de Programación 10-6 - LCMR
Conceptos básicos de Programación 10-6 - LCMRConceptos básicos de Programación 10-6 - LCMR
Conceptos básicos de Programación 10-6 - LCMR
LauraCamilaMuozRamos
 
TRABAJO TEGNOLOGICO (ISABELLA BERNAL GUETIO).pdf
TRABAJO TEGNOLOGICO (ISABELLA BERNAL GUETIO).pdfTRABAJO TEGNOLOGICO (ISABELLA BERNAL GUETIO).pdf
TRABAJO TEGNOLOGICO (ISABELLA BERNAL GUETIO).pdf
d87pgcmxqg
 
AUTOMATIZACIÓN DEL PROCESO DE MOLIENDA, MEZCLADO Y PELETIZADO EN UNA EMPRESA ...
AUTOMATIZACIÓN DEL PROCESO DE MOLIENDA, MEZCLADO Y PELETIZADO EN UNA EMPRESA ...AUTOMATIZACIÓN DEL PROCESO DE MOLIENDA, MEZCLADO Y PELETIZADO EN UNA EMPRESA ...
AUTOMATIZACIÓN DEL PROCESO DE MOLIENDA, MEZCLADO Y PELETIZADO EN UNA EMPRESA ...
AlbertoCarlosChauca2
 
IPLOOK Solución de core móvil convergente 4G&5G de punta a punta.pdf
IPLOOK Solución de core móvil convergente 4G&5G de punta a punta.pdfIPLOOK Solución de core móvil convergente 4G&5G de punta a punta.pdf
IPLOOK Solución de core móvil convergente 4G&5G de punta a punta.pdf
IPLOOK Networks
 
FOROS, BLOGS Y CHATS HERRAMIENTAS PARA LA COMUNICACIÓN VIRTUAL.pdf
FOROS, BLOGS Y CHATS HERRAMIENTAS PARA LA COMUNICACIÓN VIRTUAL.pdfFOROS, BLOGS Y CHATS HERRAMIENTAS PARA LA COMUNICACIÓN VIRTUAL.pdf
FOROS, BLOGS Y CHATS HERRAMIENTAS PARA LA COMUNICACIÓN VIRTUAL.pdf
JosGregorioFernndezA
 
PROYECTO INTEGRADOR: LAS TIC EN LA SOCIEDAD
PROYECTO INTEGRADOR: LAS TIC EN LA SOCIEDADPROYECTO INTEGRADOR: LAS TIC EN LA SOCIEDAD
PROYECTO INTEGRADOR: LAS TIC EN LA SOCIEDAD
241578066
 
FIBRA_OPTICA_EMPALMES_TIPOS_ESTRUCTURA.ppt
FIBRA_OPTICA_EMPALMES_TIPOS_ESTRUCTURA.pptFIBRA_OPTICA_EMPALMES_TIPOS_ESTRUCTURA.ppt
FIBRA_OPTICA_EMPALMES_TIPOS_ESTRUCTURA.ppt
yhimitoti
 
ALGORITMO METODO DE ORDENAMIENTO COUNTING SORT
ALGORITMO METODO DE ORDENAMIENTO COUNTING SORTALGORITMO METODO DE ORDENAMIENTO COUNTING SORT
ALGORITMO METODO DE ORDENAMIENTO COUNTING SORT
202212601a
 
fidelityhub. plataforma de desarrollo web
fidelityhub. plataforma de desarrollo webfidelityhub. plataforma de desarrollo web
fidelityhub. plataforma de desarrollo web
CristianMorles
 
Automatismos industriales Juan Martin y María Garcia.pdf
Automatismos industriales Juan Martin y María Garcia.pdfAutomatismos industriales Juan Martin y María Garcia.pdf
Automatismos industriales Juan Martin y María Garcia.pdf
AlbertoCarlosChauca2
 

Último (14)

Bifurcaciones edición 18 - eHealth (salud digital)
Bifurcaciones edición 18 - eHealth (salud digital)Bifurcaciones edición 18 - eHealth (salud digital)
Bifurcaciones edición 18 - eHealth (salud digital)
 
Tecnología Educativa en el marco formación universitaria
Tecnología Educativa en el marco formación universitariaTecnología Educativa en el marco formación universitaria
Tecnología Educativa en el marco formación universitaria
 
"Los 10 Beneficios Clave de Contratar un Asistente Virtual" pdf
"Los 10 Beneficios Clave de Contratar un Asistente Virtual" pdf"Los 10 Beneficios Clave de Contratar un Asistente Virtual" pdf
"Los 10 Beneficios Clave de Contratar un Asistente Virtual" pdf
 
tecnosaramineiropalaciosegundoperiodo.docx
tecnosaramineiropalaciosegundoperiodo.docxtecnosaramineiropalaciosegundoperiodo.docx
tecnosaramineiropalaciosegundoperiodo.docx
 
Conceptos básicos de Programación 10-6 - LCMR
Conceptos básicos de Programación 10-6 - LCMRConceptos básicos de Programación 10-6 - LCMR
Conceptos básicos de Programación 10-6 - LCMR
 
TRABAJO TEGNOLOGICO (ISABELLA BERNAL GUETIO).pdf
TRABAJO TEGNOLOGICO (ISABELLA BERNAL GUETIO).pdfTRABAJO TEGNOLOGICO (ISABELLA BERNAL GUETIO).pdf
TRABAJO TEGNOLOGICO (ISABELLA BERNAL GUETIO).pdf
 
AUTOMATIZACIÓN DEL PROCESO DE MOLIENDA, MEZCLADO Y PELETIZADO EN UNA EMPRESA ...
AUTOMATIZACIÓN DEL PROCESO DE MOLIENDA, MEZCLADO Y PELETIZADO EN UNA EMPRESA ...AUTOMATIZACIÓN DEL PROCESO DE MOLIENDA, MEZCLADO Y PELETIZADO EN UNA EMPRESA ...
AUTOMATIZACIÓN DEL PROCESO DE MOLIENDA, MEZCLADO Y PELETIZADO EN UNA EMPRESA ...
 
IPLOOK Solución de core móvil convergente 4G&5G de punta a punta.pdf
IPLOOK Solución de core móvil convergente 4G&5G de punta a punta.pdfIPLOOK Solución de core móvil convergente 4G&5G de punta a punta.pdf
IPLOOK Solución de core móvil convergente 4G&5G de punta a punta.pdf
 
FOROS, BLOGS Y CHATS HERRAMIENTAS PARA LA COMUNICACIÓN VIRTUAL.pdf
FOROS, BLOGS Y CHATS HERRAMIENTAS PARA LA COMUNICACIÓN VIRTUAL.pdfFOROS, BLOGS Y CHATS HERRAMIENTAS PARA LA COMUNICACIÓN VIRTUAL.pdf
FOROS, BLOGS Y CHATS HERRAMIENTAS PARA LA COMUNICACIÓN VIRTUAL.pdf
 
PROYECTO INTEGRADOR: LAS TIC EN LA SOCIEDAD
PROYECTO INTEGRADOR: LAS TIC EN LA SOCIEDADPROYECTO INTEGRADOR: LAS TIC EN LA SOCIEDAD
PROYECTO INTEGRADOR: LAS TIC EN LA SOCIEDAD
 
FIBRA_OPTICA_EMPALMES_TIPOS_ESTRUCTURA.ppt
FIBRA_OPTICA_EMPALMES_TIPOS_ESTRUCTURA.pptFIBRA_OPTICA_EMPALMES_TIPOS_ESTRUCTURA.ppt
FIBRA_OPTICA_EMPALMES_TIPOS_ESTRUCTURA.ppt
 
ALGORITMO METODO DE ORDENAMIENTO COUNTING SORT
ALGORITMO METODO DE ORDENAMIENTO COUNTING SORTALGORITMO METODO DE ORDENAMIENTO COUNTING SORT
ALGORITMO METODO DE ORDENAMIENTO COUNTING SORT
 
fidelityhub. plataforma de desarrollo web
fidelityhub. plataforma de desarrollo webfidelityhub. plataforma de desarrollo web
fidelityhub. plataforma de desarrollo web
 
Automatismos industriales Juan Martin y María Garcia.pdf
Automatismos industriales Juan Martin y María Garcia.pdfAutomatismos industriales Juan Martin y María Garcia.pdf
Automatismos industriales Juan Martin y María Garcia.pdf
 

Xml On Rails

  • 1. Rails y XML como herramienta de Integración obra publicada por javier ramirez como ‘Atribución-No Comercial-Licenciar Igual 2.5’ de Creative Commons [email_address]
  • 2. ¿por qué xml? ¿por qué rails? ¿cómo? integración vía REST
  • 3. estándar de facto, universal legible y flexible posibilidad de representar jerarquías ¿por qué xml?
  • 4. iteradores cómodos consola para pruebas métodos y librerías de xml en la distribución conversión automática ¿por qué rails?
  • 5. método to_xml builder XMLSimple REXML ¿cómo? generación de xml interpretación de xml
  • 6. <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> <topic> <parent-id></parent-id> <title>The First Topic</title> <author-name>David</author-name> <id type=&quot;integer&quot;>1</id> <approved type=&quot;boolean&quot;>false</approved> <replies-count type=&quot;integer&quot;>0</replies-count> <bonus-time type=&quot;datetime&quot;>2000-01-01T08:28:00+12:00</bonus-time> <written-on type=&quot;datetime&quot;>2003-07-16T09:28:00+1200</written-on> <content>Have a nice day</content> <author-email-address>david@loudthinking.com</author-email-address> <last-read type=&quot;date&quot;>2004-04-15</last-read> </topic> xml básico instruct root attribute text element
  • 7. xml desde cualquier modelo, con includes de primer nivel xml desde cualquier hash, incluso anidadas xml desde arrays si todos sus elementos responden a to_xml método to_xml..
  • 8. no soporta atributos sustitución de _ por - :root, :except, :only, :skip_instruct, :include, :indent ..método to_xml.
  • 9. permite generar cualquier xml de forma sencilla, con elementos, atributos, namespaces, contenido mixto y cualquier anidamiento permite lanzar eventos al estilo SAX builder..
  • 10. xm.html do # <html> xm.head do # <head> xm.title(&quot;History&quot;) # <title>History</title> end # </head> xm.body do # <body> xm.comment! &quot;HI&quot; # <!-- HI --> xm.h1(&quot;Header&quot;) # <h1>Header</h1> xm.p(&quot;paragraph&quot;) # <p>paragraph</p> end # </body> end # </html> ..builder..
  • 11. Builder::XmlMarkup.new :target :indent :margin instruct! (tag=:xml,attrs{}) <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> ..builder..
  • 12. comment! xm.comment! 'test' <!– test --> declare! xm.declare! :DOCTYPE :article :PUBLIC &quot;//OASIS/DTD&quot; <!DOCTYPE article PUBLIC &quot;//OASIS/DTD&quot;> cdata! xm.cdata! 'test' <![CDATA[test]]> text! para texto no escapado puede usarse xm << 'test & >' ..builder..
  • 13. method_missing xm.evento 'conferencia rails' <evento>conferencia rails</evento> xm.evento 'conferencia',:id=>1,:year=>'2006' <evento year=&quot;2006&quot; id=&quot;1&quot;>conferencia</evento> xm.RAILS :evento, 'conferencia', :year=>'2006' <RAILS:evento year=&quot;2006&quot;>conferencia</RAILS:evento> tag! ..builder..
  • 14. contenido mixto <p class=&quot;weblink&quot;>visita la web<a href= &quot;http://www.conferenciarails.org&quot;> conferencia rails</a></p> xm.p('visita la web ',:class=>'weblink') do xm.a 'conferenciarails', :href=>'http://www.conferenciarails.org' end xm.p(:class=>'weblink') do xm.text! 'visita la web' xm.a 'conferencia rails', :href=>'http://www.conferenciarails.org' end ..builder..
  • 15. en vistas rxml, accesible mediante el objeto xml para usar partials en el caller render partial=>'partial_name', :locals=>{parent_xml=>xml} en el partial xml = parent_xml unless !parent_xml ..builder.
  • 16. mapeo de xml a arrays/hashes ruby de forma sencilla depende de rexml. rexml viene con ruby y xmlsimple con rails es una adaptación de la librería perl XML::Simple xmlsimple..
  • 17. XmlSimple.xml_in nil|xml_string|filename|IO, args XmlSimple.xml_out (hash) ..xmlsimple..
  • 18. <opt> <person firstname=&quot;Joe&quot; lastname=&quot;Smith&quot;> <email>joe@smith.com</email> <email>jsmith@yahoo.com</email> </person> <person firstname=&quot;Bob&quot; lastname=&quot;Smith&quot;> <email>bob@smith.com</email> </person> </opt> { 'person' => [ { 'email' => [ 'joe@smith.com', 'jsmith@yahoo.com' ], 'firstname' => 'Joe', 'lastname' => 'Smith' }, { 'email' => ['bob@smith.com'], 'firstname' => 'Bob', 'lastname' => 'Smith' } ] } ..xmlsimple..
  • 19. ForceArray ( true |false) | ([lista]) <opt> <person><email>joe@smith.com</email></person> </opt> XmlSimple.xml_in (xml,'ForceArray'=>true) {'opt‘=>[{'person' =>[{ 'email' => [ 'joe@smith.com']}]}]} XmlSimple.xml_in (xml,'ForceArray'=>false) { ' opt'=> {'person' =>{ 'email' =>'joe@smith.com'}}} ..xmlsimple..
  • 20. KeyAttr [lista] | {elemento=>lista} <opt> <user login=&quot;grep&quot; fullname=&quot;Gary R Epstein&quot; /> <user login=&quot;stty&quot; fullname=&quot;Simon T Tyson&quot; /> </opt> xml_in (xml, { 'KeyAttr' => ‘login' }) { 'user' => { 'stty' => { 'fullname' => 'Simon T Tyson' }, 'grep' => { 'fullname' => 'Gary R Epstein' } } } xml_in (xml, { 'KeyAttr' => { 'user' => &quot;+login&quot; }}) { 'user' => { 'stty' => { 'fullname' => 'Simon T Tyson', 'login' => 'stty' }, 'grep' => { 'fullname' => 'Gary R Epstein', 'login' => 'grep' } } } ..xmlsimple..
  • 21. xml =%q( <opt> <x>text1</x> <y a=&quot;2&quot;>text2</y> </opt>) { 'x' => 'text1', 'y' => { 'a' => '2', 'content' => 'text2' } ForceContent XmlSimple.xml_in(xml, { 'ForceContent' => true }) { 'x' => { 'content' => 'text1' }, 'y' => { 'a' => '2', 'content' => 'text2' } } ContentKey XmlSimple.xml_in(xml, { 'ContentKey' => 'text' }) { 'x' => 'text1', 'y' => { 'a' => '2', ‘text' => 'text2' } ..xmlsimple..
  • 22. KeepRoot (true| false ) RootName (xml_out) def:opt OutputFile (xml_out) SupressEmpty (true|nil|’’) def:[] Variables (name=>value) ${} ..xmlsimple..
  • 23. XmlDeclaration (true|string) KeyToSymbol (true| false ) NoEscape (true| false ) NormaliseSpace ( 0 |1|2) 0: sin normalizar 1: normaliza sólo hash keys 2: normaliza todo ..xmlsimple..
  • 24. Si queremos usar varias veces los mismos parámetros de inicialización, podemos crear una instancia con las opciones deseadas my_xml = XmlSimple.new (ForceArray=>true, KeepRoot=>true) my_xml.xml_in %q(<root><H1>test</H1></root>) ..xmlsimple..
  • 25. Si recibimos un request con content-type = “application/xml” se usa xmlsimple dejando una hash en params[:root_name] Para otros content-types ActionController::Base.param_parsers [Mime::Type.lookup( 'application/xml+soap' )] = :xml_simple ..xmlsimple.
  • 26. parser xml completo.incluído en ruby soporte de xpath modelos soportados tree / dom stream / sax (push) stream / sax2 (push) stream / stax (pull) rexml..
  • 27. modelo DOM, con estilo ruby java: for (Enumeration e=parent.getChildren(); e.hasMoreElements(); ) { Element child = (Element)e.nextElement(); // Do something with child } rexml: parent.each_child { |child| # Do something with child } ..rexml..
  • 28. document.root element.each element.elements element.attributes ..rexml..
  • 29. element element.name devuelve el tag element.next_element element.previous_element element.next_sibling element.previous_sibling element.root_node ..rexml..
  • 30. elements accesible por index, desde 1 opcionalmente por index,nombre accesible por nombre. devuelve el primero con ese tag each_element_with_attribute each_element_with_text elements.to_a ..rexml..
  • 31. attributes accesible por nombre each {|key,value|} to_a ['key=value',…] ..rexml..
  • 32. xpath REXML::XPath.first (element,expr) REXML::XPath.each (element,expr) REXML::Xpath.match (element,expr) ..rexml..
  • 33. xpath desde elements elements.each (xpath_expr) elements[xpath_expr] elements.to_a (xpath_expr) ..rexml..
  • 34. ejemplos con xpath doc.elements.each('/inventory/section/item') doc.elements.each('//item[@stock='18']) doc.elements[&quot;//price[text()='14.50']/..&quot;] ..rexml..
  • 35. textos accesible mediante element.text siempre en utf-8 se sustituyen las entidades tanto XML como definidas en el DTD ..rexml..
  • 36. creación / modificación de nodos el.add_element 'item' el.add_element 'item', {'stock'=>'18'} el.text = '4.95' el.add_text '4,95' el.delete_element el.delete_attribute el['stock'] = '18' ..rexml..
  • 37. streaming parsers lanzan eventos mientras se lee el xml más rápidos que DOM y con menos consumo de memoria. útiles en documentos grandes requieren 'máquina de estados' ..rexml..
  • 38. rexml stream parser ~ sax Document.parse_stream(source, listener) métodos REXML::StreamListener tag_start / tag_end text / cdata comment entity / entitydecl doctype / doctype_end attlistdecl / elementdecl instruction / notationdecl / xmldecl ..rexml..
  • 39. sax2 parser es como el streaming parser, pero con la posibilidad de filtrar los eventos que se lanzan permite escuchar eventos vía listeners o mediante procs ..rexml..
  • 40. proceso de eventos via procs require 'rexml/sax2parser' parser = REXML::SAX2Parser.new( File.new( 'documentation.xml' ) ) parser.listen( :characters ) {|text| puts text } parser.parse parser.listen( :characters, %w{ changelog todo } ) {|text| puts text } parser.listen(%w{ item } ) {|uri,localname,qname,attributes| puts qname} ..rexml..
  • 41. proceso de eventos via listeners listener = MySAX2Listener.new parser.listen( listener ) item_listener = MySAX2Listener.new parser.listen (%w{item}, item_listener) parser.parse podemos procesar eventos mediante procs y listeners de forma combinada. Los listeners se procesan más rápidamente, pero necesitamos crear un objeto con los métodos apropiados ..rexml..
  • 42. pull parser ~ stax en lugar de escuchar eventos, se piden items y luego se comprueba su tipo requiere mantener máquina de estados, pero el código es más legible ..rexml..
  • 43. el pull parser en rexml está todavía en estado experimental parser = PullParser.new( &quot;<a>text<b att='val'/>txet</a>&quot; ) while parser.has_next? res = parser.next puts res[1]['att'] if res.start_tag? and res[0] == 'b' raise res[1] if res.error? end ..rexml.
  • 44. los servicios web son demasiado complejos para muchos casos cuando se realizan consultas, se envía menos información que la que se recibe. podemos exponer la misma api al usuario final y a la máquina REST: representational state transfer..
  • 45. modelo rails = rest resource un recurso se identifica con una uri www.example.com/item/200776 permite cachear las peticiones ya servidas ..rest..
  • 46. rest propone separar las operaciones con resources en tres partes verbo nombre content-type a diferencia de XML-RPC, el conjunto de operaciones (verbos) es limitado y hay en su lugar muchos nombres (recursos) diferentes ..rest..
  • 47. rest efectúa las operaciones CRUD mediante los verbos HTTP PUT/ GET/ POST/ DELETE el content-type puede ser cualquiera, incluso diferente para la entrada y la salida (ej: url=>xml) ..rest..
  • 48. if request.post? if params[:id] # update else # no ID # create elsif request.get? # mostrar el modelo en xml elsif request.delete? # delete end ..rest.. para distinguir la operación a realizar
  • 49. def show_item @item = Item.find(params[:id]) respond_to do |accepts| accepts.html accepts.xml {render :xml=>@item.to_xml} end end ..rest.. para poder servir al cliente diferentes content-types según su cabecera Accept:
  • 50. delegando en rails para la recepción de parámetros via querystring o xml de forma transparente (usando xmlsimple por debajo) y utilizando el mecanismo respond_to, podemos servir aplicaciones rest en diferentes formatos con el mínimo esfuerzo ..rest.
  • 51. las librerías proporcionadas en la distribución estándar de ruby on rails permiten la interpretación y la generación de xml de una forma rápida, sencilla y limpia las facilidades de prueba directa en la consola, agilizan el desarrollo como resultado, usar rails mejora la productividad cuando tratamos xml conclusión
  • 52. Rails y XML como herramienta de Integración obra publicada por javier ramirez como ‘Atribución-No Comercial-Licenciar Igual 2.5’ de Creative Commons [email_address]