Vraag Hoe System.Xml.XmlException te voorkomen: ongeldig teken in de gegeven codering


Ik heb een Windows-desktopapp geschreven in C # die door een aantal XML-bestanden loopt die zijn opgeslagen op een schijf en die zijn gemaakt door een programma van derden. De meeste bestanden worden met succes geladen en verwerkt door de LINQ-code die deze verklaring volgt:

XDocument xmlDoc = XDocument.Load(inFileName);
List<DocMetaData> docList =
      (from d in xmlDoc.Descendants("DOCUMENT")
       select new DocMetaData
       {
      File = d.Element("FILE").SafeGetAttributeValue("filename")
         ,
      Folder = d.Element("FOLDER").SafeGetAttributeValue("name")
         ,
      ItemID = d.Elements("INDEX")
          .Where(i => (string)i.Attribute("name") == "Item ID(idmId)")
          .Select(i => (string)i.Attribute("value"))
          .FirstOrDefault()
         ,
      Comment = d.Elements("INDEX")
          .Where(i => (string)i.Attribute("name") == "Comment(idmComment)")
          .Select(i => (string)i.Attribute("value"))
          .FirstOrDefault()
         ,
      Title = d.Elements("INDEX")
          .Where(i => (string)i.Attribute("name") == "Title(idmName)")
          .Select(i => (string)i.Attribute("value"))
          .FirstOrDefault()
         ,
      DocClass = d.Elements("INDEX")
          .Where(i => (string)i.Attribute("name") == "Document Class(idmDocType)")
          .Select(i => (string)i.Attribute("value"))
          .FirstOrDefault()
       }
      ).ToList<DocMetaData>();

... waarbij inFileName een volledig pad en bestandsnaam is, zoals:

     Y:\S2Out\B0000004\Pet Tab\convert.B0000004.Pet Tab.xml

Maar een paar van de bestanden veroorzaken dit soort problemen:

System.Xml.XmlException: Invalid character in the given encoding. Line 52327, position 126.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.InvalidCharRecovery(Int32& bytesCount, Int32& charsCount)
at System.Xml.XmlTextReaderImpl.GetChars(Int32 maxCharsCount)
at System.Xml.XmlTextReaderImpl.ReadData()
at System.Xml.XmlTextReaderImpl.ParseAttributeValueSlow(Int32 curPos, Char quoteChar, NodeData attr)
at System.Xml.XmlTextReaderImpl.ParseAttributes()
at System.Xml.XmlTextReaderImpl.ParseElement()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r)
at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r, LoadOptions o)
at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options)
at System.Xml.Linq.XDocument.Load(String uri, LoadOptions options)
at System.Xml.Linq.XDocument.Load(String uri)
at CBMI.WinFormsUI.GridForm.processFile(StreamWriter oWriter, String inFileName, Int32 XMLfileNumber) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 147
at CBMI.WinFormsUI.GridForm.btnProcess_Click(Object sender, EventArgs e) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 105

De XML-bestanden zien er als volgt uit (dit voorbeeld toont slechts 2 DOCUMENT-elementen, maar er zijn er veel):

<?xml version="1.0" ?>
<DOCUMENTCOLLECTION>
   <DOCUMENT>
       <FILE filename="e:\S2Out\B0000005\General\D003712420.0001.pdf" outputpath="e:\S2Out\B0000005\General"/>
       <ANNOTATION filename=""/>
       <INDEX name="Comment(idmComment)" value=""/>
       <INDEX name="Document Class(idmDocType)" value="General"/>
       <INDEX name="Item ID(idmId)" value="003712420"/>
       <INDEX name="Original File Name(idmDocOriginalFile)" value="Matrix Aligning 603.24 Criteria to Petition Pages.pdf"/>
       <INDEX name="Title(idmName)" value="Matrix for 603.24"/>
       <FOLDER name="/Accreditation/PASBVE/2004-06"/>
   </DOCUMENT>
   <DOCUMENT>
       <FILE filename="e:\S2Out\B0000005\General\D003712442.0001.pdf" outputpath="e:\S2Out\B0000005\General"/>
       <ANNOTATION filename=""/>
       <INDEX name="Comment(idmComment)" value=""/>
       <INDEX name="Document Class(idmDocType)" value="General"/>
       <INDEX name="Item ID(idmId)" value="003712442"/>
       <INDEX name="Original File Name(idmDocOriginalFile)" value="Contacts at NDU.pdf"/>
       <INDEX name="Title(idmName)" value="Contacts at NDU"/>
       <FOLDER name="/Accreditation/NDU/2006-12/Self-Study"/>
   </DOCUMENT>

De LINQ-statements hebben hun eigen complexiteiten, maar ik denk dat het goed werkt; het is de LADING die faalt. Ik heb gekeken naar de verschillende constructeurs voor XDocument Load en ik heb een aantal andere vragen met deze uitzondering onderzocht, maar ik ben in de war over hoe dit te voorkomen.

Tenslotte, op regel 52327, positie 126, in het bestand dat niet kon worden geladen, lijkt het erop dat deze gegevens op regel 52327 NIET het probleem hadden veroorzaakt (en het laatste teken op positie 103!

<FILE filename="e:\S2Out\B0000004\Pet Tab\D003710954.0001.pdf" outputpath="e:\S2Out\B0000004\Pet Tab"/>

13
2017-11-26 02:18


oorsprong


antwoorden:


Om de codering te besturen (als je eenmaal weet wat het is), kun je de bestanden laden met behulp van de Load methode-override die a accepteert Stream.

Vervolgens kunt u een nieuwe maken StreamReader tegen uw bestand met vermelding van de juiste Encoding in de constructor.

Als u bijvoorbeeld het bestand wilt openen met West-Europese codering, vervangt u de volgende regel met code in de vraag:

XDocument xmlDoc = XDocument.Load(inFileName);

met deze code:

XDocument xmlDoc = null;

using (StreamReader oReader = new StreamReader(inFileName, Encoding.GetEncoding("ISO-8859-1"))) {
    xmlDoc = XDocument.Load(oReader);
}

De lijst met ondersteunde coderingen is te vinden in de MSDN-documentatie.


31
2017-11-26 02:34



Niet zeker of dit uw geval is, maar dit kan te maken hebben met ongeldige byte-reeksen voor een gegeven codering. Voorbeeld: http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences.

Probeer tijdens het laden ongeldige reeksen uit het bestand te filteren.


2
2017-11-26 03:07



Het bestand waarnaar wordt verwezen bevat een teken dat geldig is voor een bestandsnaam, maar dat ongeldig is in een XML-kenmerk. Je hebt een paar opties.

  1. U kunt de bestandsnaam wijzigen en uw script van derden opnieuw uitvoeren.
  2. U zou met de leverancier kunnen samenwerken om een ​​patch te bieden die de aanstootgevende karakters veilig codeert.
  3. U kunt de XML-documenten vooraf valideren en de aanstootgevende vermeldingen verwijderen voordat ze worden verwerkt.

1
2017-11-26 02:46



Omdat XmlDocument het hele ding laadt zodra het een ongecodeerd teken tegenkomt, wordt het hele proces afgebroken. Als je wilt verwerken wat je kunt en duff-bits overslaan / loggen, kijk dan naar XmlTextReader. XmlTextReader geladen vanuit een Filestream laadt een knoop tegelijkertijd, dus het zal ook veel minder geheugen gebruiken. Je zou zelfs slim kunnen worden en het ding opsplitsen en de verwerking parallel maken.

Toen ik dit had, waren het dingen als geaccentueerde karakters daar: graf, acutes, umlauts en dergelijke.

Ik heb geen geautomatiseerde processen, dus meestal laad ik het bestand gewoon in Visual Studio en redigeer de slechteriken totdat er geen squigglies meer over is. De theorie is echter gezond.


1
2017-11-26 02:36