M.L.Casellas
27-06-2012, 23:12:46
Hola;
Abro este nuevo hilo, porque considero que es mejor a la hora de que alguien busque información sobre este tema. En un anterior hilo (http://clubdelphi.com/foros/showthread.php?t=79288) pedía ayuda para leer los ficheros .xml que DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp) devuelve al hacerle llamadas http. El título de ese hilo no es descriptivo para el tema en cuestión y además es algo lioso, lo siento.
Y también, para colaborar y poder ayudar a otros aquí en la comunidad :)
Así que, aquí va este hilo que es la forma en que ya he solucionado el problema, y para que pueda servir a alguien más que en un futuro necesite programar (para una librería por ejemplo, como es mi caso) llamadas a DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp).
Así es como yo he conseguido hacerlo al final, y va estupendamente, al instante, en 1 segundo tengo los datos que quiero del ISBN solicitado, es una maravilla ;)
Bueno, al grano:
Después de comprarme y leerme la mitad del libro XML-Edición 2012 (http://www.casadellibro.com/libro-xml-edicion-2012-manual-imprescindible/9788441529601/1895764) de Miguel Ángel Acera García (http://seindor.com/maacera.com/acerca-de-miguel-angel-acera-3?utm_expid=26280487-1&utm_referrer=http%3A%2F%2Fwww.google.es%2Furl%3Fsa%3Dt%26rct%3Dj%26q%3Dmiguel%2520%25C3%25A1ngel%252 0acera%2520garc%25C3%25ADa%26source%3Dweb%26cd%3D1%26ved%3D0CFIQFjAA%26url%3Dhttp%253A%252F%252Fsein dor.com%252Fmaacera.com%252F%26ei%3DBXXrT__sBITDtAb3i_nPBQ%26usg%3DAFQjCNGQxmfLyf0oTsjs0eAE7hHZyHDbU g), buscar info por internet etc…etc…He conseguido aprender bastante sobre el XML y como tratarlo en Delphi.
El asunto en cuestión es pedir a DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp) los datos de un libro, enviándoles el código ISBN. Si la llamada es correcta, ellos devuelven un fichero en formato .XML con la ficha de dicho libro.
DILVE trabajan con el formato internacional ONIX for Books (http://www.editeur.org/8/ONIX/) (Del cual me he bajado y leido parte de la documentación).
Bien, lo primero que hago es la llamada a la URL con los parametros adecuados:
XMLDocument1.LoadFromFile(‘http://www.dilve.es/dilve/dilve/getRecordsX.do?user=*************&password=***********&identifier=9788467036350&metadataformat=ONIX&version=3.0 (http://www.dilve.es/dilve/dilve/getRecordsX.do?user=mnavarrorico01&password=KGW44S67&identifier=9788467036350&metadataformat=ONIX&version=3.0)’);
URL de DILVE + La llamada “getRecordsX” que es la que pide un sólo registro + Nombre de usuario + Contraseña + Identificador(el ISBN/Cod.Barras) + El formato que deseamos (ONIX etiquetas largas, ONIX, etiquetas cortas, CSV….) + La versión que queremos (DILVE trabaja internamente con la 2.1 que ya es antigua, pero también sirve la 3.0 que es la actual).
Después ejecuto el procedure que he creado para la carga de los datos:
XmlToMe(XMLDocument1.DocumentElement);
Y el procedure es el siguiente (va con comentarios):
procedure TFormPrincipal.XmlToKios(XmlNode: IXMLNode);
var
I: Integer;
I2: Integer;
NodeText: String;
AttrNode: IXMLNode;
Atributos: String;
AutorPerson, AutorPersonInverted: Boolean;
begin
AutorPerson := False;
AutorPersonInverted := False;
// Desechamos nodos que no sean elements
if XmlNode.NodeType <> ntElement then
Exit;
// Asignamos el nombre del nodo a la variable
NodeText:= XmlNode.NodeName;
// Comprobamos si la cabecera es correcta o devuelve error
if XmlNode.NodeName = 'ONIXMessage' then
for I := 0 to XmlNode.AttributeNodes.Count - 1 do // leemos los parametros
begin
AttrNode:= XmlNode.AttributeNodes.Nodes[I];
Atributos := Atributos + ' ' + AttrNode.NodeName + '=' + '"' + AttrNode.Text + '"';
end;
Caption := Caption + ' <' + XmlNode.NodeName + Atributos + '>';
end;
// Si la respuesta es error, se muestra un mensaje con el código y texto del error
if XmlNode.NodeName = 'error' then
begin
errores := True;
end;
// Comprobamos el tipo de notificación. '03' es para fichas completas. El
// resto pueden ser updates y otros...
// la etiqueta 'Product' es repetible si se piden listados, en este caso es
// Existen etiquetas que se llaman igual dentro de distintos bloques, por
// lo que hay que comprobar que cuelgan del adecuado
if (XmlNode.NodeName = 'NotificationType') and
(XmlNode.ParentNode.NodeName = 'Product') then
begin
if Not (XmlNode.NodeValue = '03') then
begin
ShowMessage('No se trata de una ficha completa de libro');
errores := True;
end;
end;
// Ahora ya comenzamos a leer los campos que nos interesan
// TITULO
if (XmlNode.NodeName = 'TitleDetail') and
(XmlNode.ParentNode.NodeName = 'DescriptiveDetail') and
(XmlNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['TitleType'].Text = '01') then
begin
XmlNode := XmlNode.ChildNodes['TitleElement'];
if XmlNode.ChildNodes['TitleElementLevel'].Text = '01' then
begin
EditTitulo.Text := XmlNode.ChildNodes['TitleText'].Text;
end;
end;
// AUTOR/ES
// Aquí pueden estar las dos etiquetas a la vez: inverted y normal
// me decanto por la Inverted
if (XmlNode.NodeName = 'Contributor') and
(XmlNode.ParentNode.NodeName = 'DescriptiveDetail') and
(XmlNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['ContributorRole'].Text = 'A01') then
begin
//Recorremos todos los child para ver los que hay
for I2 := 0 to XmlNode.ChildNodes.Count - 1 do
begin
if XmlNode.ChildNodes[I2].NodeName = 'PersonName' then
begin
AutorPerson := True;
end;
if XmlNode.ChildNodes[I2].NodeName = 'PersonNameInverted' then
begin
AutorPersonInverted := True;
end;
end;
// Según las etiquetas, si está la opción Inverted la utlizamos prioritariamente
if AutorPersonInverted then
begin
if EditAutores.GetTextLen > 0 then
begin
EditAutores.Text := EditAutores.Text + ' | ' + XmlNode.ChildNodes['PersonNameInverted'].Text;
end else
begin
EditAutores.Text := XmlNode.ChildNodes['PersonNameInverted'].Text;
end;
end else
if AutorPerson then
begin
if EditAutores.GetTextLen > 0 then
begin
EditAutores.Text := EditAutores.Text + ' | ' + XmlNode.ChildNodes['PersonName'].Text;
end else
begin
EditAutores.Text := XmlNode.ChildNodes['PersonName'].Text;
end;
end;
end;
// EDITORIAL
if (XmlNode.NodeName = 'Publisher') and
(XmlNode.ParentNode.NodeName = 'PublishingDetail') and
(XmlNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['PublishingRole'].Text = '01') then
begin
EditCodEditorial.Text := XmlNode.ChildNodes['PublisherIdentifier'].ChildNodes['IDValue'].Text;
EditEditorial.Text := XmlNode.ChildNodes['PublisherName'].Text;
end;
// PRECIO CON IVA
if (XmlNode.NodeName = 'Price') and
(XmlNode.ParentNode.NodeName = 'SupplyDetail') and
(xmlNode.ParentNode.ParentNode.NodeName = 'ProductSupply') and
(XmlNode.ParentNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['CurrencyCode'].Text = 'EUR') and
(XmlNode.ChildNodes['PriceType'].Text = '04') then
begin
EditPvp.Text := XmlNode.ChildNodes['PriceAmount'].Text + ' €';
end;
// EL IVA (%)
if (XmlNode.NodeName = 'Tax') and
(XmlNode.ParentNode.NodeName = 'Price') and
(XmlNode.ParentNode.ParentNode.NodeName = 'SupplyDetail') and
(XmlNode.ParentNode.ParentNode.ParentNode.NodeName = 'ProductSupply') and
(XmlNode.ParentNode.ParentNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['TaxType'].Text = '01') then
begin
EditIva.Text := XmlNode.ChildNodes['TaxRatePercent'].Text + ' %';
end;
// Recorremos los nodos hijos si lo hay
if XmlNode.HasChildNodes then
for I := 0 to XmlNode.ChildNodes.Count - 1 do
XmlToKios(XmlNode.ChildNodes.Nodes[I]);
// Si ha habido errores, limpiamos los edits
if errores then
begin
LimpiarCampos.Execute;
end;
// Deberiamos capturar el error enviado por el servidor en formato .xml
// y mostrar el mensaje adecuado, según la tabla de DILVE, ya que estos
// pueden ser de conexión, mantenimiento del servidor, isbn no encontrado,
// isbn mal formado, etc.
// ¿Que tal si preguntamos en el ClubDelphi? ¡Vale! Vamos allá.......
end;
Lo que hago es recorrer el documento. Apenas tarda un segundo (se tarda mucho más en dar de alta el libro a mano).
Decir que hay campos (nodos) que son repetibles y ya dependen de otros nodos hijo, del código que lleven.
Me falta alguna cosilla en realidad, y se trata del tema de errores. Veréis: si hago esta llamada desde el Internet Explorer y el ISBN o existe por ejemplo, pues el IE se queda en blanco, mostrando una pantalla de error propia, pero no recoge el .xml de error que envía DILVE (ya meré en ver código fuente de la página)……. ¡Firefox si lo hace! Firefox si, y así pude recoger el .xml en cuestión para ver como era.
Entonces, yo me preguntaba que ocurriría en mi codigo……pues…..al estilo IE …no me llega el .xml de error.
Lo suyo sería poder recoger ese .xml de error y procesarlo según la tabla de errores de DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp), para saber si es por mantenimiento del servidor, isbn no encontrado, etc. De momento, pues muestro un error general.
¿Alguien sabe hacer para que mi llamada recoja el .xml de error? Ese .xml lleva la cabecera como el otro, pero después sólo lleva 2 datos: el número de error y una descripción (en inglés).
Bueno, espero que esto pueda servir de ayuda a alguien. Por supuesto, para probarlo hace falta tener User y Password de DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp). Yo utilizo la de la librería para quien hago esto. Pero aquí queda, para quien llegara a encontrarse en mi situación y buscara info.
Y por supuesto, seguro que este código es mejorable, así que cualquier consejo, sugerencia, lo que sea, lo agradecería
¡Un saludo!
Abro este nuevo hilo, porque considero que es mejor a la hora de que alguien busque información sobre este tema. En un anterior hilo (http://clubdelphi.com/foros/showthread.php?t=79288) pedía ayuda para leer los ficheros .xml que DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp) devuelve al hacerle llamadas http. El título de ese hilo no es descriptivo para el tema en cuestión y además es algo lioso, lo siento.
Y también, para colaborar y poder ayudar a otros aquí en la comunidad :)
Así que, aquí va este hilo que es la forma en que ya he solucionado el problema, y para que pueda servir a alguien más que en un futuro necesite programar (para una librería por ejemplo, como es mi caso) llamadas a DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp).
Así es como yo he conseguido hacerlo al final, y va estupendamente, al instante, en 1 segundo tengo los datos que quiero del ISBN solicitado, es una maravilla ;)
Bueno, al grano:
Después de comprarme y leerme la mitad del libro XML-Edición 2012 (http://www.casadellibro.com/libro-xml-edicion-2012-manual-imprescindible/9788441529601/1895764) de Miguel Ángel Acera García (http://seindor.com/maacera.com/acerca-de-miguel-angel-acera-3?utm_expid=26280487-1&utm_referrer=http%3A%2F%2Fwww.google.es%2Furl%3Fsa%3Dt%26rct%3Dj%26q%3Dmiguel%2520%25C3%25A1ngel%252 0acera%2520garc%25C3%25ADa%26source%3Dweb%26cd%3D1%26ved%3D0CFIQFjAA%26url%3Dhttp%253A%252F%252Fsein dor.com%252Fmaacera.com%252F%26ei%3DBXXrT__sBITDtAb3i_nPBQ%26usg%3DAFQjCNGQxmfLyf0oTsjs0eAE7hHZyHDbU g), buscar info por internet etc…etc…He conseguido aprender bastante sobre el XML y como tratarlo en Delphi.
El asunto en cuestión es pedir a DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp) los datos de un libro, enviándoles el código ISBN. Si la llamada es correcta, ellos devuelven un fichero en formato .XML con la ficha de dicho libro.
DILVE trabajan con el formato internacional ONIX for Books (http://www.editeur.org/8/ONIX/) (Del cual me he bajado y leido parte de la documentación).
Bien, lo primero que hago es la llamada a la URL con los parametros adecuados:
XMLDocument1.LoadFromFile(‘http://www.dilve.es/dilve/dilve/getRecordsX.do?user=*************&password=***********&identifier=9788467036350&metadataformat=ONIX&version=3.0 (http://www.dilve.es/dilve/dilve/getRecordsX.do?user=mnavarrorico01&password=KGW44S67&identifier=9788467036350&metadataformat=ONIX&version=3.0)’);
URL de DILVE + La llamada “getRecordsX” que es la que pide un sólo registro + Nombre de usuario + Contraseña + Identificador(el ISBN/Cod.Barras) + El formato que deseamos (ONIX etiquetas largas, ONIX, etiquetas cortas, CSV….) + La versión que queremos (DILVE trabaja internamente con la 2.1 que ya es antigua, pero también sirve la 3.0 que es la actual).
Después ejecuto el procedure que he creado para la carga de los datos:
XmlToMe(XMLDocument1.DocumentElement);
Y el procedure es el siguiente (va con comentarios):
procedure TFormPrincipal.XmlToKios(XmlNode: IXMLNode);
var
I: Integer;
I2: Integer;
NodeText: String;
AttrNode: IXMLNode;
Atributos: String;
AutorPerson, AutorPersonInverted: Boolean;
begin
AutorPerson := False;
AutorPersonInverted := False;
// Desechamos nodos que no sean elements
if XmlNode.NodeType <> ntElement then
Exit;
// Asignamos el nombre del nodo a la variable
NodeText:= XmlNode.NodeName;
// Comprobamos si la cabecera es correcta o devuelve error
if XmlNode.NodeName = 'ONIXMessage' then
for I := 0 to XmlNode.AttributeNodes.Count - 1 do // leemos los parametros
begin
AttrNode:= XmlNode.AttributeNodes.Nodes[I];
Atributos := Atributos + ' ' + AttrNode.NodeName + '=' + '"' + AttrNode.Text + '"';
end;
Caption := Caption + ' <' + XmlNode.NodeName + Atributos + '>';
end;
// Si la respuesta es error, se muestra un mensaje con el código y texto del error
if XmlNode.NodeName = 'error' then
begin
errores := True;
end;
// Comprobamos el tipo de notificación. '03' es para fichas completas. El
// resto pueden ser updates y otros...
// la etiqueta 'Product' es repetible si se piden listados, en este caso es
// Existen etiquetas que se llaman igual dentro de distintos bloques, por
// lo que hay que comprobar que cuelgan del adecuado
if (XmlNode.NodeName = 'NotificationType') and
(XmlNode.ParentNode.NodeName = 'Product') then
begin
if Not (XmlNode.NodeValue = '03') then
begin
ShowMessage('No se trata de una ficha completa de libro');
errores := True;
end;
end;
// Ahora ya comenzamos a leer los campos que nos interesan
// TITULO
if (XmlNode.NodeName = 'TitleDetail') and
(XmlNode.ParentNode.NodeName = 'DescriptiveDetail') and
(XmlNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['TitleType'].Text = '01') then
begin
XmlNode := XmlNode.ChildNodes['TitleElement'];
if XmlNode.ChildNodes['TitleElementLevel'].Text = '01' then
begin
EditTitulo.Text := XmlNode.ChildNodes['TitleText'].Text;
end;
end;
// AUTOR/ES
// Aquí pueden estar las dos etiquetas a la vez: inverted y normal
// me decanto por la Inverted
if (XmlNode.NodeName = 'Contributor') and
(XmlNode.ParentNode.NodeName = 'DescriptiveDetail') and
(XmlNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['ContributorRole'].Text = 'A01') then
begin
//Recorremos todos los child para ver los que hay
for I2 := 0 to XmlNode.ChildNodes.Count - 1 do
begin
if XmlNode.ChildNodes[I2].NodeName = 'PersonName' then
begin
AutorPerson := True;
end;
if XmlNode.ChildNodes[I2].NodeName = 'PersonNameInverted' then
begin
AutorPersonInverted := True;
end;
end;
// Según las etiquetas, si está la opción Inverted la utlizamos prioritariamente
if AutorPersonInverted then
begin
if EditAutores.GetTextLen > 0 then
begin
EditAutores.Text := EditAutores.Text + ' | ' + XmlNode.ChildNodes['PersonNameInverted'].Text;
end else
begin
EditAutores.Text := XmlNode.ChildNodes['PersonNameInverted'].Text;
end;
end else
if AutorPerson then
begin
if EditAutores.GetTextLen > 0 then
begin
EditAutores.Text := EditAutores.Text + ' | ' + XmlNode.ChildNodes['PersonName'].Text;
end else
begin
EditAutores.Text := XmlNode.ChildNodes['PersonName'].Text;
end;
end;
end;
// EDITORIAL
if (XmlNode.NodeName = 'Publisher') and
(XmlNode.ParentNode.NodeName = 'PublishingDetail') and
(XmlNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['PublishingRole'].Text = '01') then
begin
EditCodEditorial.Text := XmlNode.ChildNodes['PublisherIdentifier'].ChildNodes['IDValue'].Text;
EditEditorial.Text := XmlNode.ChildNodes['PublisherName'].Text;
end;
// PRECIO CON IVA
if (XmlNode.NodeName = 'Price') and
(XmlNode.ParentNode.NodeName = 'SupplyDetail') and
(xmlNode.ParentNode.ParentNode.NodeName = 'ProductSupply') and
(XmlNode.ParentNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['CurrencyCode'].Text = 'EUR') and
(XmlNode.ChildNodes['PriceType'].Text = '04') then
begin
EditPvp.Text := XmlNode.ChildNodes['PriceAmount'].Text + ' €';
end;
// EL IVA (%)
if (XmlNode.NodeName = 'Tax') and
(XmlNode.ParentNode.NodeName = 'Price') and
(XmlNode.ParentNode.ParentNode.NodeName = 'SupplyDetail') and
(XmlNode.ParentNode.ParentNode.ParentNode.NodeName = 'ProductSupply') and
(XmlNode.ParentNode.ParentNode.ParentNode.ParentNode.NodeName = 'Product') and
(XmlNode.ChildNodes['TaxType'].Text = '01') then
begin
EditIva.Text := XmlNode.ChildNodes['TaxRatePercent'].Text + ' %';
end;
// Recorremos los nodos hijos si lo hay
if XmlNode.HasChildNodes then
for I := 0 to XmlNode.ChildNodes.Count - 1 do
XmlToKios(XmlNode.ChildNodes.Nodes[I]);
// Si ha habido errores, limpiamos los edits
if errores then
begin
LimpiarCampos.Execute;
end;
// Deberiamos capturar el error enviado por el servidor en formato .xml
// y mostrar el mensaje adecuado, según la tabla de DILVE, ya que estos
// pueden ser de conexión, mantenimiento del servidor, isbn no encontrado,
// isbn mal formado, etc.
// ¿Que tal si preguntamos en el ClubDelphi? ¡Vale! Vamos allá.......
end;
Lo que hago es recorrer el documento. Apenas tarda un segundo (se tarda mucho más en dar de alta el libro a mano).
Decir que hay campos (nodos) que son repetibles y ya dependen de otros nodos hijo, del código que lleven.
Me falta alguna cosilla en realidad, y se trata del tema de errores. Veréis: si hago esta llamada desde el Internet Explorer y el ISBN o existe por ejemplo, pues el IE se queda en blanco, mostrando una pantalla de error propia, pero no recoge el .xml de error que envía DILVE (ya meré en ver código fuente de la página)……. ¡Firefox si lo hace! Firefox si, y así pude recoger el .xml en cuestión para ver como era.
Entonces, yo me preguntaba que ocurriría en mi codigo……pues…..al estilo IE …no me llega el .xml de error.
Lo suyo sería poder recoger ese .xml de error y procesarlo según la tabla de errores de DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp), para saber si es por mantenimiento del servidor, isbn no encontrado, etc. De momento, pues muestro un error general.
¿Alguien sabe hacer para que mi llamada recoja el .xml de error? Ese .xml lleva la cabecera como el otro, pero después sólo lleva 2 datos: el número de error y una descripción (en inglés).
Bueno, espero que esto pueda servir de ayuda a alguien. Por supuesto, para probarlo hace falta tener User y Password de DILVE (http://www.dilve.es/dilve/dilveweb/index_dilve.jsp). Yo utilizo la de la librería para quien hago esto. Pero aquí queda, para quien llegara a encontrarse en mi situación y buscara info.
Y por supuesto, seguro que este código es mejorable, así que cualquier consejo, sugerencia, lo que sea, lo agradecería
¡Un saludo!