Laden...

Linq to XML basierend auf Attributen mit Namespace

Erstellt von Skeptar vor 7 Jahren Letzter Beitrag vor 7 Jahren 1.373 Views
S
Skeptar Themenstarter:in
5 Beiträge seit 2016
vor 7 Jahren
Linq to XML basierend auf Attributen mit Namespace

Hallo,
zurzeit Versuche ich bestimmte Werte aus eine XML-Datei (erstellt von LibreOffice-Writer) auszulesen. Gerne würde ich mir die Werte mit der Technik "Linq to XML" aus der .xml Datei heraussuchen.

Die xml-Datei könnte z.B. wie folgt aussehen:

<?xml version="1.0" encoding="UTF-8" ?>
<office:document-content office:version="1.2"
	xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
	xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
	xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">
  <office:body>
    <office:text>
      <table:table table:name="Tabelle6" table:style-name="Tabelle6">
        <table:table-row>
          <table:table-cell table:style-name="Tabelle6.A1" office:value-type="string">
            <text:p text:name="Invoice" text:style-name="P6">0001</text:p>
          </table:table-cell>
		  <table:table-cell table:style-name="Tabelle6.A1" office:value-type="string">
            <table:table-cell table:style-name="Tabelle6.A1" office:value-type="string">
				<text:p text:style-name="P6"></text:p>
			</table:table-cell>
			<table:table-cell table:style-name="Tabelle6.A1" office:value-type="string">
				<text:p text:name="TotalAmount" text:style-name="P6">23,58€</text:p>
			</table:table-cell>
          </table:table-cell>
        </table:table-row>
      </table:table>
    </office:text>
  </office:body>
</office:document-content>

In diesem Beispiel möchte ich nun die beiden Werte 0001 (Invoice) und 23,58€ (TotalAmount) haben.

Nun habe ich angefangen das Problem zu lösen jedoch komme ich nicht ganz zurecht mit den Linq 'Zeugs'.

string filePath = AppDomain.CurrentDomain.BaseDirectory + @"\process\content.xml";

    var xml = XDocument.Load(filePath);
    var root = xml.Root;
    var elements = root.Descendants().Where(ex => ex.Name.LocalName == "p");

Nachdem Stückchen Code befindet sich in elements folgendes:

<text:p text:name="Invoice" text:style-name="P6">0001</text:p>
<text:p text:style-name="P6"></text:p>
<text:p text:name="TotalAmount" text:style-name="P6">23,58€</text:p>

Nun könnte ich mit einer foreach Schleife in Inhalt von elements durchlaufen und mit

string.contains

die relevanten Einträge heraussuchen. Das finde ich aber um ehrlich zu sein nicht schön, da es anscheinend auch mit 'Linq to XML' funktioniert.

Um z.B. die Rechnungsnummer (invoice) herauszufiltern habe ich:

string invoice = elements.Where(a => a.Attribute("name").Value == "Invoice").Select(a => a.Value).ToString();

versucht. Nachdem ausführen steht in der Variable

invoice

aber nur der Typ(?) ->

System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Xml.Linq.XElement,System.String]

Eventuell hat der ein oder andere von euch ja eine Idee.

3.003 Beiträge seit 2006
vor 7 Jahren


var xDoc = XDocument.Load(filename);

XNamespace textNs = "text";

var nodes = xDoc.Root.Descendants(textNs + "p").Where(node => node.Attribute("name") != null).Select(node => new { Name = node.Attribute("name").Value, Value = node.Value });

Nicht getestet, da kann jetzt 'n Flüchtigkeitsfehler drin sein. Jedenfalls: Namespaceangabe mit namespace + "nodename".

LaTino
EDIT: versuch beim Umgang mit Linq mit deiner Datenquelle zu reden, in natürlicher Sprache. "Gib mir von den "p"-Knoten mit dem Namespace "text" alle mit einem "name"-Attribut, als Listenzuordnung von ihrem Namen und ihrem Wert". Wenn du in "foreach" denkst, bist du falsch abgebogen und befindest dich nicht mehr in der deklarativen Welt von Linq.
EDIT2: kleine Korrektur

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

S
Skeptar Themenstarter:in
5 Beiträge seit 2016
vor 7 Jahren

Hallo LaTino,
danke für die Antwort.

Ich habe es versucht, jedoch komme ich zu keinem Ergebnis.

Bis zu dem Punkt

var nodes = xDoc.Root.Descendants(textNs + "p").Where(node => node.Attribute("name") != null)

verstehe ich das soweit.

Ich denke der weitere Teil wird einfach nur ein Objekt vom Typ Node erzeugen und dort den Wert eintragen. //korrigiere mich wenn ich falsch liege

Ich habe noch einige mal von der Variable textNs gebrauch gemacht.

var nodes = xml.Root.Descendants(textNs + "p").Where(node => node.Attribute(textNs + "name") != null).Select(node => new { Name = node.Attribute(textNs + "name").Value, Value = node.Value });

Allerdings ist nodes nach ausführen null.

Jetzt habe ich noch einmal ziemlich lange das Internet durchsucht, bekomme auch viele Treffer, bekomme es aber nicht richtig zusammen gepuzzelt.

Eventuell kannst Du mir noch ein weiteres mal helfen.

5.658 Beiträge seit 2006
vor 7 Jahren

Hi Skeptar,

textNs + "p"  
textNs + "name"  

Da kommt nicht das bei raus, was du erwartest.

Da braucht man auch nicht lange im Internet suchen und "puzzeln". Sowas erkennt man, wenn man mit dem Debugger überprüft, was der Code eigentlich macht: [Artikel] Debugger: Wie verwende ich den von Visual Studio?

Weeks of programming can save you hours of planning

3.003 Beiträge seit 2006
vor 7 Jahren

(Die Schritte, um den Fehler zu finden, wären gewesen:

  1. ausprobieren (debugger!), ob xml.Root.Descendants(textNs + "p") drei Knoten liefert
  2. XNamespace in der MSDN nachschauen, evtl nach "urn" + "XNamespace" + "Linq to XMl" googeln
  3. Namespace korrigieren

var xDoc = XDocument.Parse(xml);
XNamespace textNs = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
var linqExample = xDoc.Root
    .Descendants(textNs + "p")
    .Where(node => node.Attribute(textNs + "name") != null)
    .ToDictionary(p => p.Attribute(textNs + "name").Value, p => p.Value);

Seit Visual Studio auch Linq debuggen kann, reicht eine (Debug, dann Schnellüberwachung-)Sitzung und ein bisschen herumprobieren.

LaTino
EDIT: nein, der weitere Teil erzeugt keinen Knoten. Er wählt nur existierende Knoten aus.

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)