Durante el desarrollo de una aplicación de escritorio para la radio de Douban, encontré un desafío al analizar la lista de canales de DJs de la estación. El código JavaScript extraído de la web contenía la siguiente estructura:
canales.dj = [{"canal_id":"l3","nombre":"¿Cuál fue su canción famosa?"},{"canal_id":"113044","nombre":"Susurros suaves","marca_tiempo":"1333103365.0","actualizar":0},{"canal_id":"115987","nombre":"Voz del jazz","marca_tiempo":"1333952457.0","actualizar":0},{"canal_id":"106379","nombre":"Sonidos tiernos","marca_tiempo":"1330493624.0","actualizar":0},{"canal_id":"116154","nombre":"Zihan Ann","marca_tiempo":"1334220284.0","actualizar":0},{"canal_id":"119300","nombre":"Ruido negro","marca_tiempo":"1332596519.0","actualizar":0},{"canal_id":"103756","nombre":"Zhou Zhun","marca_tiempo":"1310296419.0","actualizar":0},{"canal_id":"113914","nombre":"Subi","marca_tiempo":"1334727058.0","actualizar":0},{"canal_id":"118974","nombre":"iPlay","marca_tiempo":"1332410472.0","actualizar":0},{"canal_id":"104001","nombre":"En espera","marca_tiempo":"1322014846.0","actualizar":0},{"canal_id":"l1","nombre":"Facelook"},{"canal_id":"123048","nombre":"Ondas caseras","marca_tiempo":"1329186348.0","actualizar":0},{"canal_id":"113380","nombre":"Transmisión de relajación","marca_tiempo":"1335229294.0","actualizar":0},{"canal_id":"104524","nombre":"FM O.U.R","marca_tiempo":"1332233929.0","actualizar":0},{"canal_id":"111880","nombre":"Triceratops","marca_tiempo":"1333598037.0","actualizar":0},{"canal_id":"112177","nombre":"Maestro Jun","marca_tiempo":"1335334224.0","actualizar":0},{"canal_id":"103547","nombre":"A Peng","marca_tiempo":"1317363315.0","actualizar":0},{"canal_id":"106166","nombre":"Radio música offshore","marca_tiempo":"1329901317.0","actualizar":0},{"canal_id":"119466","nombre":"¡Lo siento! FM","marca_tiempo":"1324311596.0","actualizar":0},{"canal_id":"116241","nombre":"Estación de frecuencia malvada","marca_tiempo":"1328582570.0","actualizar":0},{"canal_id":"l2","nombre":"La cinta se rompió"},{"canal_id":"105062","nombre":"ACHA","marca_tiempo":"1333435761.0","actualizar":0},{"canal_id":"110186","nombre":"Fuera de las listas","marca_tiempo":"1319694482.0","actualizar":0},{"canal_id":"121068","nombre":"Zóteng Yueji","marca_tiempo":"1325663931.0","actualizar":0},{"canal_id":"114014","nombre":"Suburbios","marca_tiempo":"1331610037.0","actualizar":0},{"canal_id":"118673","nombre":"IndiePower","marca_tiempo":"1333171142.0","actualizar":0},{"canal_id":"121069","nombre":"666","marca_tiempo":"1321876995.0","actualizar":0},{"canal_id":"116351","nombre":"Rêveur Ailé","marca_tiempo":"1329894116.0","actualizar":0},{"canal_id":"120705","nombre":"Radio Tangsuan","marca_tiempo":"1319420901.0","actualizar":0},{"canal_id":"117447","nombre":"SICK RADIO","marca_tiempo":"1323311571.0","actualizar":0},{"canal_id":"121379","nombre":"China electrónica","marca_tiempo":"1328175960.0","actualizar":0},{"canal_id":"118962","nombre":"CT-808","marca_tiempo":"1308483701.0","actualizar":0}];
Para analizar este código, se requireen varios conocimientos técnicos: 1. Expresiones regulares, necesarias para extraer el código relevante de la página web. 2. Operaciones de deserialización JSON.
Este artículo se centra en el segundo problema que encontré:
El código anterior no es un objeto JSON típico, sino un array de objetos JSON. Utilizar los métodos de deserialización estándar para objetos JSON no produce el resultado esperaod, ya que el compilador genera errores como "se esperaba un elemento 'root' del namespace ''. Se encontró un elemento 'None' o 'deserialización de objeto' de tipo 'Doubaner.DBFM.DJChannel' con el nombre '', namespace ''. Se encontró un carácter inesperado 'c'". Los mensajes de error del compilador rara vez son útiles para resolver el problema, y la documentación de MSDN no está clara al respecto.
Después de dos días de búsqueda sin encontrar una solución adecuada, finalmente descubrí el abordaje correcto en un programa similar en línea:
En la clase que define la operación de deserialización, debemos crear una nueva clase que herede de List genérico. De esta manera, el compilador puede deserializar correctamente el array de código.
A continuación se presentna las secciones clave del código:
ListaCanalesDJ lista = new ListaCanalesDJ(); // Clase personalizada para lista de canales DJ, hereda de List<CanalesDJ>
try
{
DataContractJsonSerializer serializador = new DataContractJsonSerializer(typeof(ListaCanalesDJ));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(coincidencia.Groups[1].Value));
//string a = new StreamReader(ms).ReadToEnd();
lista = (ListaCanalesDJ)serializador.ReadObject(ms);
}
catch (Exception ex)
{
UtilidadesRegistro.Registro(ex.ToString());
}
/// <summary>
/// Clase de canal DJ
/// </summary>
[DataContract]
class CanalesDJ
{
/// <summary>
/// ID del canal
/// </summary>
[DataMember(Name="canal_id")]
public string canal {get;set;}
/// <summary>
/// Nombre del canal
/// </summary>
[DataMember(Name="nombre")]
public string nombre {get;set;}
/// <summary>
///
/// </summary>
[DataMember]
public string marca_tiempo { get; set; }
[DataMember]
public string actualizar { get; set; }
}
internal class ListaCanalesDJ : List<CanalesDJ> { }