2010-02-12 5 views
1

Je travaille sur un bug mystérieux dans le très bon projet open source Excel Data Reader. Il ignore les valeurs lues à partir de ma feuille de calcul OpenXML .xlsx particulière.Correction de problèmes XmlReader en utilisant ReadToDescendant et/ou ReadElementContentAsObject

Le problème se produit dans le ReadSheetRow method (code de démonstration ci-dessous). Le code source XML est enregistré par Excel et ne contient aucun espace qui correspond au comportement étrange. Toutefois, le format XML qui a été reformaté avec des espaces (par exemple, dans Visual Studio, accédez à Edition, Avancé, Format Document) fonctionne parfaitement!

données de test avec des espaces:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> 
    <sheetData> 
     <row r="5" spans="1:73" s="7" customFormat="1"> 
      <c r="B5" s="12"> 
       <v>39844</v> 
      </c> 
      <c r="C5" s="8"/> 
      <c r="D5" s="8"/> 
      <c r="E5" s="8"/> 
      <c r="F5" s="8"/> 
      <c r="G5" s="8"/> 
      <c r="H5" s="12"> 
       <v>39872</v> 
      </c> 
      <c r="I5" s="8"/> 
      <c r="J5" s="8"/> 
      <c r="K5" s="8"/> 
      <c r="L5" s="8"/> 
      <c r="M5" s="8"/> 
      <c r="N5" s="12"> 
       <v>39903</v> 
      </c> 
     </row> 
    </sheetData> 
</worksheet> 

données de test sans espace:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheetData><row r="5" spans="1:73" s="7" customFormat="1"><c r="B5" s="12"><v>39844</v></c><c r="C5" s="8"/><c r="D5" s="8"/><c r="E5" s="8"/><c r="F5" s="8"/><c r="G5" s="8"/><c r="H5" s="12"><v>39872</v></c><c r="I5" s="8"/><c r="J5" s="8"/><c r="K5" s="8"/><c r="L5" s="8"/><c r="M5" s="8"/><c r="N5" s="12"><v>39903</v></c></row></sheetData></worksheet> 

code exemple qui illustre le problème:

Notez que Un est sorti après _xmlReader.Read(), B après ReadToDescendant, et C après ReadElementContentAsObject.

while (reader.Read()) 
{ 
    if (reader.NodeType != XmlNodeType.Whitespace) outStream.WriteLine(String.Format("*A* NodeType: {0}, Name: '{1}', Empty: {2}, Value: '{3}'", reader.NodeType, reader.Name, reader.IsEmptyElement, reader.Value)); 

    if (reader.NodeType == XmlNodeType.Element && reader.Name == "c") 
    { 
     string a_s = reader.GetAttribute("s"); 
     string a_t = reader.GetAttribute("t"); 
     string a_r = reader.GetAttribute("r"); 

     bool matchingDescendantFound = reader.ReadToDescendant("v"); 
     if (reader.NodeType != XmlNodeType.Whitespace) outStream.WriteLine(String.Format("*B* NodeType: {0}, Name: '{1}', Empty: {2}, Value: '{3}'", reader.NodeType, reader.Name, reader.IsEmptyElement, reader.Value)); 
     object o = reader.ReadElementContentAsObject(); 
     if (reader.NodeType != XmlNodeType.Whitespace) outStream.WriteLine(String.Format("*C* NodeType: {0}, Name: '{1}', Empty: {2}, Value: '{3}'", reader.NodeType, reader.Name, reader.IsEmptyElement, reader.Value)); 
    } 
} 

Les résultats des tests pour XML avec des espaces:

 
*A* NodeType: XmlDeclaration, Name: 'xml', Empty: False, Value: 'version="1.0" encoding="UTF-8" standalone="yes"' 
*A* NodeType: Element, Name: 'worksheet', Empty: False, Value: '' 
*A* NodeType: Element, Name: 'sheetData', Empty: False, Value: '' 
*A* NodeType: Element, Name: 'row', Empty: False, Value: '' 
*A* NodeType: Element, Name: 'c', Empty: False, Value: '' 
*B* NodeType: Element, Name: 'v', Empty: False, Value: '' 
*A* NodeType: EndElement, Name: 'c', Empty: False, Value: '' 
*A* NodeType: Element, Name: 'c', Empty: True, Value: '' 
*B* NodeType: Element, Name: 'c', Empty: True, Value: '' 
... 

Les résultats des tests pour XML sans espaces:

 
*A* NodeType: XmlDeclaration, Name: 'xml', Empty: False, Value: 'version="1.0" encoding="UTF-8" standalone="yes"' 
*A* NodeType: Element, Name: 'worksheet', Empty: False, Value: '' 
*A* NodeType: Element, Name: 'sheetData', Empty: False, Value: '' 
*A* NodeType: Element, Name: 'row', Empty: False, Value: '' 
*A* NodeType: Element, Name: 'c', Empty: False, Value: '' 
*B* NodeType: Element, Name: 'v', Empty: False, Value: '' 
*C* NodeType: EndElement, Name: 'c', Empty: False, Value: '' 
*A* NodeType: Element, Name: 'c', Empty: True, Value: '' 
*B* NodeType: Element, Name: 'c', Empty: True, Value: '' 
... 

Les changements de modèle indiquent un problème dans ReadElementContentAsObject ou peut-être la emplacement que ReadToDescendant déplace le XmlReader à.

Est-ce que quelqu'un sait ce qui pourrait se passer ici?

+0

Alors, avez-vous passé en revue la source de Excel Data Reader? Vous semblez impliquer que le problème réside là-dedans ... –

+0

@silky: Oui, mon code démo est la même logique.Soit le code n'utilise pas XmlReader correctement ou il y a un bogue dans XmlReader. Très probablement le premier mais je ne peux pas voir ce qui ne va pas. –

Répondre

1

C'est assez simple. Comme vous pouvez le voir sur la sortie, la première fois que vous êtes sur la ligne "B", vous êtes positionné sur le premier élément "v". Ensuite, vous appelez ReadElementContentAsObject. Cela renvoie le contenu du texte de v, et "déplace le lecteur après la balise d'élément de fin." (de v). Vous pointez maintenant sur un nœud d'espace s'il y a un espace ou sur un nœud EndElement (de c) s'il n'y en a pas. Bien sûr, votre sortie n'imprime pas si c'est un espace. De toute façon, vous faites ensuite un Read() et passez à l'élément suivant. Dans le cas du non-espace, vous avez perdu l'EndElement.

Le problème est bien pire dans d'autres situations. Lorsque vous faites un ReadElementContentAsObject d'un c (appelez-le c1), vous passez ensuite au c suivant (c2). Ensuite, vous faites une lecture, en passant à c3, et perdez c2 pour de bon. Je ne vais pas essayer de résoudre le real code. Mais il est clair que vous devez vous soucier de faire avancer le courant à plus d'un endroit. C'est une source commune d'erreurs de bouclage en général.