Python Script in C# umwandeln

Robin F.

Neues Mitglied
Hallo zusammen,

ich habe eine XML Datei die ich mit C# auslesen und weiterverarbeiten
will.
Da ich in C# nicht weiter gekommen bin, habe ich erstmal die Datei in
Python so ausgelesen wie ich es will.
from xml.dom import minidom
xmldoc = minidom.parse("test.xml")
ctables = xmldoc.getElementsByTagName("ComplexTable")
for table in ctables:
tabletype = table.getAttribute("TableType")
subtables = table.getElementsByTagName("SubTable")
if tabletype == "Wirelist":
print("-" * 40)
print("Wirelist")
print("-" * 40)
for subtable in subtables:
rows = subtable.getElementsByTagName("Row")
for row in rows:
cells = row.getElementsByTagName("Cell")
for cell in cells:
text = cell.getAttribute("Text")
textName = text
print(textName, end=" ")
print("")
print("-" * 40)

Jetzt würde ich den Code gern in C# übersetzen aber ich komme hier nicht
weiter. Der Code sie aktuell wie folgt aus:
{
class Program
{
static void Main(string[] args)
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load("Test.xml");
XmlNodeList cTables = xdoc.GetElementsByTagName("ComplexTable");
foreach (XmlNode table in cTables)
{
string tableType = table.Attributes["TableType"].Value;
Console.WriteLine(tableType);
XmlNodeList subTables = xdoc.GetElementsByTagName("SubTable");
if (tableType == "Wirelist")
{
foreach (XmlNode subTable in subTables)
{
XmlNodeList rows = xdoc.GetElementsByTagName("Row");
foreach (XmlNode row in rows)
{
XmlNodeList cells = xdoc.GetElementsByTagName("Cell");
foreach (XmlNode cell in cells)
{
string text = cell.Attributes["Text"].Value;
Console.Write(text + " ");
}
Console.WriteLine("-------------");
}
}
}
}
Console.ReadKey();
}
}
}

Problem ist hier jetzt das ich mit der Ausgabe
string text = cell.Attributes["Text"].Value;
immer alle "ComplexTable" ausgebe und das zu einer Endlosschleife wird.
Ich will aber nur die "ComplexTabe" auslesen die das Attribute TableType
= Wirelist hat.
Ich denke zu wissen das es and dem xdoc.GetElementsByTagName(); liegt,
weil ich ja immer auf das gesamte Dokument zugreife aber ich kann nicht
wie in Python aus der foreach Schleife auf das XmlNode zurückgreifen. Da
kommt eine Fehlermeldung das XmlNode keine GetElementsByTagName
Definition enthält.

Hat einer einen Idee wie ich eine bestimmte ComplexTable auslesen kann?

Danke und Gruß
Robin
 
Es ist generell eine sehr dumme Idee, zu versuchen, algorithmische Probleme durch eine andere Programmiersprache zu lösen, denn davon verschwindet das Problem nicht.
Selbiges gilt für "Ich übersetze ein Skript von einer Sprache in die andere". Meist kommt damit furchtbarer Code raus, und es wäre weit besser, ihn gleich idiomatisch neu zu schreiben.

Aus deinem Code geht leider auch nicht hervor, welche XML-Bibliothek du da verwendest, ich nehme einfach mal an, dass es sich um System.Xml .

Generell lädst du mit System.Xml eine Datei wie folgt :

Laden eines XML-Dokuments:
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
try {
  doc.Load("booksData.xml");
} catch (System.IO.FileNotFoundException) {
  ...
}

Beachte dass ich dort die Whitespaces erhalten lasse(ist gut falls man es mal wieder ausgeben will) und vor allem die mögliche Exception abfange, sowas sollte man nicht einfach durchgaloppieren lassen.
Wenn es schnell sein soll und du nur einmal Daten extrahieren willst solltest du auch lieber die Klasse XMLReader verwenden, statt alles im RAM zu halten

Idealerweise ist der Folgeschritt dann, das XML mit einem XML-Schema zu validieren(das lasse ich hier mal weg, ist in der Praxis aber extrem wichtig!)

Zur Adressierung der Elemente bietet System.Xml nun im wesentlichen zwei Möglichkeiten: die eine iteriert einfach über Children/Siblings/Parents, die andere verwendet, wie scheinbar du hier, XPath. Da du dein XML hier nicht hochgeladen hast, kann ich nicht sagen, was genau an deinem XPath nicht stimmt, aber generell findest du Beispiele wie man an die Elemente kommt und was man damit tun kann hier : https://docs.microsoft.com/en-us/dotnet/api/system.xml?view=net-5.0, bzw. falls du noch .Net Core 3.1 verwendest hier : https://docs.microsoft.com/en-us/dotnet/api/system.xml?view=netcore-3.1

Alternativ bietet sich da natürlich mit System.Data.DataSet.ReadXml (https://docs.microsoft.com/en-us/dotnet/api/system.data.dataset?view=net-5.0 , die Funktion hat noch einige ähnliche Freunde) in Verbindung mit einem XMLReader eine viel viel idiomatischere und eigentlich komplett überlegene Methode an, die dir viel von dem nervigen Navigieren direkt abnehmen kann und bei der du auch die Validierung per Schema direkt in der Pipeline hast.

P.S. Benutz saubere Codetags, so kann das ja niemand lesen ;)
 
Zuletzt bearbeitet:
Hallo,

danke erstmal für die Antwort.
Sorry für die falschen Codetags. Ich bin normalerweise in einem anderen Forum unterwegs, wo mir aber keiner helfen konnte und die verwenden andere.

Ja ich verwende die System.XML Bibliothek.
Die XML Datei werde ich mal etwas ausdünnen, sodass die Struktur weitestgehend erhalten bleibt aber der Inhalt raus ist (sehr sensible Daten und über 17000 Zeilen).

Der Wechsel zu Python war nur um herauszufinden ob es generell funktioniert, die XML auslesen zu können oder ob ich dazu überhaupt nicht in der Lage bin.

Hier nochmal der gesamte C# Code:

kompletter C# Script:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace XML {
class Program {
  static void Main(string[] args) {
    XmlDocument xdoc = new XmlDocument();
    xdoc.Load("Test.xml");

    XmlNodeList cTables = xdoc.GetElementsByTagName("ComplexTable");

    foreach (XmlNode table in cTables) {
      string tableType = table.Attributes["TableType"].Value;
      Console.WriteLine(tableType);

      XmlNodeList subTables = xdoc.GetElementsByTagName("SubTable");

      if (tableType == "Wirelist") {
        foreach (XmlNode subTable in subTables) {
          XmlNodeList rows = xdoc.GetElementsByTagName("Row");
          foreach (XmlNode row in rows) {
            XmlNodeList cells = xdoc.GetElementsByTagName("Cell");
            foreach (XmlNode cell in cells) {
              string text = cell.Attributes["Text"].Value;
              Console.Write(text + " ");
            }
            Console.WriteLine("-------------");
          }
        }
      }
    }
    Console.ReadKey();
  }
}
} // namespace XML

Die XML Datei bearbeite ich wie gesagt gerade und lade sie dann hier hoch.
Ich lese mir dann auch gleich mal deine Verlinkungen durch und schaue das ich damit was anfangen kann :)

Danke schonmal für alles.
 
So ich habe die XML Datei jetzt fertig.

Zur Erklärung:
Ich habe mehrere ComplexeTable, die haben SubTable und darunter Row sowie Cell Tags.
Ich möchte nur die CompexTable mit dem Attribute "Wirelist" (Zeile 180) und eine weitere ComplexTable mit einem anderen Attribute (BOM - Zeile 349) auslesen.
Ziel ist es die Daten in ein Excel Dokument einzupflegen (ich will jedes mal eine neue Tabelle erstellen).
In der Excel Datei sollen alle Inhalte von dem Attribute "Text" in dem Tag "Cell" geschrieben werden.

Die XML ist jedes mal eine andere aber der Aufbau der XML ist jedes mal gleich (evtl. ein paar ComplexTables mehr oder weniger aber die Struktur ist gleich).

Die XML Datei ist jetzt durch das löschen einiger Informationen kaputt, ich hoffe es reicht wenn die Struktur nur ersichtlich ist.
 

Anhänge

  • Test2.txt
    34,4 KB · Aufrufe: 434
Wenn das in irgendeiner Form Produktivcode werden soll ... Dann bei allem was dir heilig ist, lern zuerst XMLs zu verarbeiten, bevor du dich auf Real-World-Daten stürzt ;)
Wenn es Produktiv ist ist übrigens auch die Validierung mit einem Schema ziemlich alternativlos.

Und wenn dein Ziel Excel ist würde ich irgendwie wetten, dass primitives XML-Handling ohnehin die falsche Wahl ist, du solltest dich da mal nach passenden Bibliotheken umsehen, gibt bestimmt welche die da Interop können(im Zweifel gibt es Microsoft.Office.Interop.Excel, aber wenn die ist wie die von Word ist das keine besonders schöne Erfahrung). Wie genau das bei C# ist weiß ich nicht, ich gehöre zur F#-Fraktion, aber zumindest für F# gibts einen TypeProvider für Excel, der sich ziemlich gut für sowas macht.
 
So ich habe das Problem lösen können. Anstatt "xdoc.GetElementsByTagName":
C# falsch:
XmlNodeList subTables = xdoc.GetElementsByTagName("SubTable");
      if (tableType == "Wirelist") {
        foreach (XmlNode subTable in subTables) {
          XmlNodeList rows = xdoc.GetElementsByTagName("Row");
          foreach (XmlNode row in rows) {
            XmlNodeList cells = xdoc.GetElementsByTagName("Cell");
            foreach (XmlNode cell in cells) {
              string text = cell.Attributes["Text"].Value;
              Console.Write(text + " ");
            }
muss ich "SelectNodes" verwenden:
C# richtig:
XmlNodeList subTables = table.SelectNodes("SubTable");
      if (tableType == "Wirelist") {
        foreach (XmlNode subTable in subTables) {
          XmlNodeList rows = subTable .SelectNodes("Row");
          foreach (XmlNode row in rows) {
            XmlNodeList cells = row.SelectNodes("Cell");
            foreach (XmlNode cell in cells) {
              string text = cell.Attributes["Text"].Value;
              Console.Write(text + " ");
            }

Danke für die Hilfe!
 
Zurück
Oben Unten