2011-07-07 25 views
6

Parsuję niektóre pliki XML od zewnętrznego dostawcy i niestety nie zawsze jest to dobrze sformatowany kod XML, ponieważ czasami niektóre elementy zawierają zduplikowane atrybuty.Jak usunąć zduplikowane atrybuty z kodu XML za pomocą C#

Nie mam kontroli nad źródłem i nie wiem, które elementy mogą mieć zduplikowane atrybuty, ani nie znam z góry zduplikowanych nazw atrybutów.

Oczywiście ładowanie zawartości do obiektu XMLDocument podnosi XmlException w dwóch egzemplarzach atrybuty więc chociaż mógłbym użyć XmlReader do kroku chociaż elementu XML przez elementu i radzić sobie z duplikat atrybuty kiedy się do elementu naruszającego.

Jednak XmlException został podniesiony na reader.Read() - zanim otrzymam szansę na odszukanie atrybutów elementu.

Oto przykładowy sposób, aby wykazać problem:

public static void ParseTest() 
{ 
    const string xmlString = 
     @"<?xml version='1.0'?> 
     <!-- This is a sample XML document --> 
     <Items dupattr=""10"" id=""20"" dupattr=""33""> 
      <Item>test with a child element <more/> stuff</Item> 
     </Items>"; 

    var output = new StringBuilder(); 
    using (XmlReader reader = XmlReader.Create(new StringReader(xmlString))) 
    { 
     XmlWriterSettings ws = new XmlWriterSettings(); 
     ws.Indent = true; 
     using (XmlWriter writer = XmlWriter.Create(output, ws)) 
     { 
      while (reader.Read()) /* Exception throw here when Items element encountered */ 
      { 
       switch (reader.NodeType) 
       { 
        case XmlNodeType.Element: 
         writer.WriteStartElement(reader.Name); 
         if (reader.HasAttributes){ /* CopyNonDuplicateAttributes(); */} 
         break; 
        case XmlNodeType.Text: 
         writer.WriteString(reader.Value); 
         break; 
        case XmlNodeType.XmlDeclaration: 
        case XmlNodeType.ProcessingInstruction: 
         writer.WriteProcessingInstruction(reader.Name, reader.Value); 
         break; 
        case XmlNodeType.Comment: 
         writer.WriteComment(reader.Value); 
         break; 
        case XmlNodeType.EndElement: 
         writer.WriteFullEndElement(); 
         break; 
       } 
      } 

     } 
    } 
    string str = output.ToString(); 
} 

Czy istnieje inny sposób na analizę danych wejściowych i usunąć duplikaty atrybutów bez konieczności używania wyrażeń regularnych i łańcuchach?

+0

Może być to możliwe tylko wtedy, gdy dostawca procesora XML procesora posiada jakiekolwiek haki, które pozwalają na przechwycenie i przetworzenie błędów. – Ankur

+0

Interesujący problem, czekamy na rozwiązanie! –

+2

Nie będzie rozwiązania tego problemu za pomocą XML, ponieważ twoje dane wejściowe nie są danymi XML. Mówisz, że nie masz kontroli nad danymi wejściowymi, ale czy możesz przynajmniej poinformować przełożonych, że twój dostawca nie wysyła Ci XML? Czy możesz przynajmniej upewnić się, że twój _vendor_ wie o tym?Każda organizacja na tyle głupia, aby wysłać te dane, może być na tyle głupia, by nie zdawać sobie sprawy, że to nie XML. –

Odpowiedz

3

Znalazłem rozwiązanie, myśląc o XML jako dokumencie HTML. Następnie korzystając z biblioteki open-source Html Agility Pack, udało mi się uzyskać poprawny XML.

Sztuką było najpierw zapisać xml z nagłówkiem HTML.
więc zastąpić deklarację XML
<?xml version="1.0" encoding="utf-8" ?>
z deklaracją HTML tak:
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Gdy zawartość są zapisywane do pliku, metoda ta zwróci ważnego dokumentu XML.

// Requires reference to HtmlAgilityPack 
public XmlDocument LoadHtmlAsXml(string url) 
{ 
    var web = new HtmlWeb(); 

    var m = new MemoryStream(); 
    var xtw = new XmlTextWriter(m, null); 

    // Load the content into the writer 
    web.LoadHtmlAsXml(url, xtw); 

    // Rewind the memory stream 
    m.Position = 0; 

    // Create, fill, and return the xml document 
    XmlDocument xmlDoc = new XmlDocument(); 
    xmlDoc.LoadXml((new StreamReader(m)).ReadToEnd()); 
    return xmlDoc; 
} 

duplikatów węzłów atrybutu automatycznie usuwane z późniejszym wartości atrybutów zastępując wcześniejsze.

0

Ok że trzeba złapać błąd:

to powinieneś być w stanie korzystać z następujących metod:

reader.MoveToFirstAttribute(); 

i

reader.MoveToNextAttribute() 

uzyskać następujące właściwości:

reader.Value 
reader.Name 

Pozwoli to uzyskać wszystkie wartości atrybutów.

+0

Mogę złapać błąd i przetworzyć atrybuty na bieżącym węźle (tzn. Skopiować nie duplikaty), ale problem nadal trwa, przetwarzając resztę dokumentu, ponieważ 'read.Read()' zwraca wartość false, więc nie są przetwarzane żadne dodatkowe elementy. – Catch22

+0

# Catch22, tak natknąłem się na to, próbując odzyskać kod. Miałem nadzieję, że znajdziesz sposób na obejście tego. Zajrzyj tutaj: http://bytes.com/topic/c-sharp/answers/827965-how-handle-xml-parsing-exception Wygląda na to, że XMLReader jest nietolerancyjny z jakiegoś powodu. Zazwyczaj będzie to dobra wiadomość, ale w twoim przypadku oznacza to, że moje sugerowane rozwiązanie prawdopodobnie nie zadziała. Przepraszam – openshac

Powiązane problemy