tipos - try catch finally c# ejemplos
La instrucción Try-Catch finaliza mientras lee en bucle a través de un archivo XML en C# (4)
Tengo un ciclo while pasando por un archivo XML, y para uno de los nodos "url", a veces hay valores no válidos dentro de él. Puse una declaración try-catch alrededor de esto para capturar cualquier valor inválido. El problema es que cada vez que se toma un valor no válido, el bucle while se elimina y el programa continúa fuera de ese bucle. Necesito el ciclo while para seguir leyendo el resto del archivo XML después de encontrar un valor no válido.
Aquí está mi código:
XmlTextReader reader = new XmlTextReader(fileName);
int tempInt;
while (reader.Read())
{
switch (reader.Name)
{
case "url":
try
{
reader.Read();
if (!reader.Value.Equals("/r/n"))
{
urlList.Add(reader.Value);
}
}
catch
{
invalidUrls.Add(urlList.Count);
}
break;
}
}
Elegí no incluir el resto de la declaración de cambio ya que no es relevante. Aquí hay una muestra de mi XML:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<visited_links_list>
<item>
<url>http://www.grcc.edu/error.cfm</url>
<title>Grand Rapids Community College</title>
<hits>20</hits>
<modified_date>10/16/2012 12:22:37 PM</modified_date>
<expiration_date>11/11/2012 12:22:38 PM</expiration_date>
<user_name>testuser</user_name>
<subfolder></subfolder>
<low_folder>No</low_folder>
<file_position>834816</file_position>
</item>
</visited_links_list>
La excepción que obtengo a lo largo del código es similar a lo siguiente:
"'''', valor hexadecimal 0x05, es un carácter no válido. Línea 3887, posición 13."
Tengo la sensación de que el reader
se queda en un estado defectuoso después de que se lanza la excepción (como reader.Read();
(dentro del switch
, no el while
) es muy probable que sea la línea en la que ocurrió la excepción. Luego, el reader.Read()
en el while
no devuelve nada, y sale.
Hice un simple switch
en una aplicación de consola y capté y excepción en él y el bucle que lo contiene continúa.
var s = "abcdefg";
foreach (var character in s)
{
switch (character)
{
case ''c'':
try
{
throw new Exception("c sucks");
}
catch
{
// Swallow the exception and move on?
}
break;
default:
Console.WriteLine(character);
break;
}
}
Si recorre el código, ¿intenta ejecutar reader.Read()
en el while
después de capturar la excepción?
Use continue
while (reader.Read())
{
switch (reader.Name)
{
case "url":
try
{
reader.Read();
if (!reader.Value.Equals("/r/n"))
{
urlList.Add(reader.Value);
}
}
catch
{
invalidUrls.Add(urlList.Count);
continue;
}
break;
}
}
Observación:
reader.Read()
a reader.Read()
dos veces para cada entrada. Una vez en while()
, y una vez dentro del case
. ¿Realmente quieres omitir los registros? Esto causará una excepción si hay un número impar de entradas en el código fuente XML (ya que reader.Read()
avanza el puntero dentro de la secuencia XML al próximo elemento), pero esa excepción no se detectará porque ocurre fuera de su try...catch
.
Más allá de eso:
reader.Read(); /// might return false, but no exception, so keep going...
if (!reader.Value.Equals("/r/n")) /// BOOM if the previous line returned false, which you ignored
{
urlList.Add(reader.Value);
}
/// reader is now in unpredictable state
Editar
A riesgo de escribir una nueva respuesta de longitud ...
El error que recibes
"'''', valor hexadecimal 0x05, es un carácter no válido. Línea 3887, posición 13."
indica que su fuente XML está mal formada, y de alguna manera terminó con un ^E
(ASCII 0x05) en la posición especificada. Echaré un vistazo a esa línea. Si obtiene este archivo de un proveedor o un servicio, debe hacer que corrija el código. Corrigiendo eso, y cualquier otro contenido mal formado dentro de su XML, debería corregir el problema que está viendo.
Una vez que se solucione, su código original debería funcionar. Sin embargo, usar XmlTextReader
para esto no es la solución más robusta e implica construir algún código que Visual Studio pueda generar para usted:
En VS2012 (no tengo VS2010 instalado más, pero debería ser el mismo proceso):
Agregue una muestra del XML a su solución
En las propiedades de ese archivo, configure CustomTool en "MSDataSetGenerator" (sin las comillas)
El IDE debe generar un archivo .designer.cs, que contenga una clase serializable con un campo para cada elemento en el XML. (De lo contrario, haga clic con el botón derecho en el archivo XML en el explorador de soluciones y seleccione "Ejecutar herramienta personalizada").
Use un código como el siguiente para cargar XML con el mismo esquema que su muestra en tiempo de ejecución:
/// make sure the XML doesn''t have errors, such as non-printable characters private static bool IsXmlMalformed(string fileName) { var reader = new XmlTextReader(fileName); var result = false; try { while (reader.Read()) ; } catch (Exception e) { result = true; } return result; } /// Process the XML using deserializer and VS-generated XML proxy classes private static void ParseVisitedLinksListXml(string fileName, List<string> urlList, List<int> invalidUrls) { if (IsXmlMalformed(fileName)) throw new Exception("XML is not well-formed."); using (var textReader = new XmlTextReader(fileName)) { var serializer = new XmlSerializer(typeof(visited_links_list)); if (!serializer.CanDeserialize(textReader)) throw new Exception("Can''t deserialize this XML. Make sure the XML schema is up to date."); var list = (visited_links_list)serializer.Deserialize(textReader); foreach (var item in list.item) { if (!string.IsNullOrEmpty(item.url) && !item.url.Contains(Environment.NewLine)) urlList.Add(item.url); else invalidUrls.Add(urlList.Count); } } }
También puede hacer esto con la herramienta XSD.exe incluida con el SDK de Windows.
Supongo que está leyendo un documento xml válido como myFile.xml. También estoy asumiendo que "url" es el elemento que buscas obtener.
Cargue el documento en una clase XMLDocument y utilícelo para atravesar los nodos. Esto debería eliminar los caracteres incorrectos, ya que los convertirá en el formato correcto, como & se convertirá en amplificador; ect ..
el método a continuación debería funcionar dando el ejemplo que proporcionó.
//get the text of the file into a string
System.IO.StreamReader sr = new System.IO.StreamReader(@"C:/test.xml");
String xmlText = sr.ReadToEnd();
sr.Close();
//Create a List of strings and call the method
List<String> urls = readXMLDoc(xmlText);
//check to see if we have a list
if (urls != null)
{
//do somthing
}
private List<String> readXMLDoc(String fileText)
{
//create a list of Strings to hold our Urls
List<String> urlList = new List<String>();
try
{
//create a XmlDocument Object
XmlDocument xDoc = new XmlDocument();
//load the text of the file into the XmlDocument Object
xDoc.LoadXml(fileText);
//Create a XmlNode object to hold the root node of the XmlDocument
XmlNode rootNode = null;
//get the root element in the xml document
for (int i = 0; i < xDoc.ChildNodes.Count; i++)
{
//check to see if it is the root element
if (xDoc.ChildNodes[i].Name == "visited_links_list")
{
//assign the root node
rootNode = xDoc.ChildNodes[i];
break;
}
}
//Loop through each of the child nodes of the root node
for (int j = 0; j < rootNode.ChildNodes.Count; j++)
{
//check for the item tag
if (rootNode.ChildNodes[j].Name == "item")
{
//assign the item node
XmlNode itemNode = rootNode.ChildNodes[j];
//loop through each if the item tag''s elements
foreach (XmlNode subNode in itemNode.ChildNodes)
{
//check for the url tag
if (subNode.Name == "url")
{
//add the url string to the list
urlList.Add(subNode.InnerText);
}
}
}
}
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
return null;
}
//return the list
return urlList;
}