Windows PS: durch Verzeichnisbaum iterien

ral9004

Lt. Junior Grade
Registriert
Dez. 2017
Beiträge
503
Hallo

Ich versuche auf die Elemente einer ".opf" Datei zugreifen (XML).
Die Datei Metadata.opf ist korrekt parameterisiert:
Code:
<?xml version='1.0' encoding='utf-8'?>
<package xmlns="http://www.idpf.org/2007/opf" unique-identifier="uuid_id" version="2.0">
    <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">

Nach verschiedenen Versuchen habe ich soeben folgendes Erlebnis.
Versuch1:
ps-xml-1.png

Element "Title" wird ausgeben Rest ignoriert.

Versuch2:
ps-xml-2.png

Wieder Element "Title" wird ausgeben Rest ignoriert. Aber... die Formatierung der Ausgabe hat sich nur auf Grund der Reihenfolge im Powershell Code verändert. Was ist das für eine Logik?

Hat dazu jemand weiterführende Informationen?

Nur um Spekulationen vorzubeugen. Die Datei "metadata.opf" wird von der Applikation automatisch erstellt. Keine handgestrickte Datei.

Beste Grüsse
 
Du verwendest return. Das gibt immer den Wert zurück und beendet dann sofort die Ausführung des Skriptes. Das ist keine Besonderheit von MS PS, sondern klassisches Verhalten von Programmiersprachen. Wenn du alle drei Elemente anzeigen willst, benutz Write-Output. Probier das (ich habe eine eigene opf-Datei zum Testen genommen):

>> [xml] $foo = gc test1.opf >> Write-Output $foo.package.metadata.title >> Write-Output $foo.package.metadata.creator >> Write-Output $foo.package.metadata.publisher

Wenn du den Wert zurückgeben willst, stopf die Daten in ein Array und gib das zurück. Du kannst nicht mehrere Werte nacheinander zurückgeben.
 
  • Gefällt mir
Reaktionen: ral9004
Warum in ein Array packen, wenn sie bereits semantisch sinnvoll in $foo.package.metadata stecken?

Und creator ist halt auch ein Objekt mit mehreren Properties. Was man anhand des XMLs auch direkt hätte sagen können, aber der Teil wurde im Sinne best möglicher Hilfsmöglichkeiten einfach weggelassen.
 
tollertyp schrieb:
Warum in ein Array packen, wenn sie bereits semantisch sinnvoll in $foo.package.metadata stecken?
Weil eventuell nicht die kompletten Metadaten gebraucht werden? Spielt bei so einem File sicher nicht wirklich eine Rolle, aber ich für meinen Teil versuche immer zu optimieren, wo es geht. Ansonsten wollte ich einen gewissen Teil des Denkens für den OP übriglassen, aber mach du das ruhig anders.

tollertyp schrieb:
Und creator ist halt auch ein Objekt mit mehreren Properties.
Du meinst sicher Element und Attribute?
 
Ich meine ein Objekt aus Programmier-Sicht. Ein Element mit Attributen ist XML.
Und selbst wenn metadata "zu viel" Informationen hat, wieso ein Array und keinen Typ (Objekt) liefern mit passenden Properties?

Was sagt mehr aus?
$metadata[0] oder $metadata.title
 
Hab ich irgendwas von numerischem Array gesagt? Ich halte Arrays für anfängerfreundlicher, das ist alles. Mir musst du wirklich nicht erklären, wie man das macht.
 
ral9004 schrieb:
Wieder Element "Title" wird ausgeben Rest ignoriert. Aber... die Formatierung der Ausgabe hat sich nur auf Grund der Reihenfolge im Powershell Code verändert. Was ist das für eine Logik?

Hat dazu jemand weiterführende Informationen?
a) ist wohl ein Irrtum, nach dem 1. return ist immer Schluss, s.o.
b) du hast $opf.package.metadata.creator ausgegeben, hier bekommst du nicht einen Einzelwert sondern ein Objekt zurück, weil das Element weitere Unterelemente in der XML Datei hatte.
Für die Ausgabe eines Objekt auf der Konsole wird geschaut, welcher Standardformatierer dafür definiert ist.
Da du $opf explizit auf [xml] gecastet hast wird der dafür definierte Formatierer genommen und eine Tabelle ausgedruckt, deren Spalten die einzelnen Attribute (hier: direkte Kindelemente) sind.

Willst du nur den Wert eines bestimmtes Unterelements in der Ausgabe haben, musst du das auch direkt ansteuern indem du den Elementnamen an das jeweilige Elternelement anhängst
Code:
$opf.package.metadata.creator.hutzliputz
hutzliputz muss dann aber wieder in der XML Datei ein Element sein, das nicht weiter verschachtelt ist, dann kriegst du direkt den Wert der im Tag drin war (= einen String), sonst gibt es wieder ein XML Objekt.
 
f00bar schrieb:
..benutz Write-Output. Probier das (ich habe eine eigene opf-Datei zum Testen genommen):

>> [xml] $foo = gc test1.opf >> Write-Output $foo.package.metadata.title >> Write-Output $foo.package.metadata.creator >> Write-Output $foo.package.metadata.publisher
Hallo f00bar

Danke. Wieder etwas gelernt. Mit "Write-Output" erhalte ich den Output
Das Element oder "Tag" namens "Creator" hat zwei Attribute:

<dc:creator opf:file-as="Moorcock, Michael" opf:role="aut">Michael Moorcock</dc:creator>

Frage 1
Ich erhalte den Wert des Attributes "opf:role="aut", wenn ich mit "'#text' ergänze.
write-output $opf.package.metadata.creator.'#text'

Ich habe die Spezifikation gelesen. Dort steht nichts von "#text".
https://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.2.2

PS und get-help verraten mir diesen Sachverhalt nicht.
Wenn ich das im Kontext von PS ergooglen will, erhalte ich ganze zwei Treffer ohne Erklärung
ps-xml-4.png

Wie komme ich hier an meine Informationen?

Frage 2:
Auch hier wieder der nebensächliche Effekt, dass der Output anders aussieht, wenn man bei diesen drei Elementen (oder Tags) zuerst "Creator" ausgibt. Oder im zweiten Beispiel, wenn "Creator erst als zweites Element ausgeben wird. Warum?

ps-xml-3.png


Beste Grüsse



Beste Grüsse
Ergänzung ()

lokked schrieb:
Willst du nur den Wert eines bestimmtes Unterelements in der Ausgabe haben, musst du das auch direkt ansteuern indem du den Elementnamen an das jeweilige Elternelement anhängst
Code:
$opf.package.metadata.creator.hutzliputz
hutzliputz muss dann aber wieder in der XML Datei ein Element sein, das nicht weiter verschachtelt ist, dann kriegst du direkt den Wert der im Tag drin war (= einen String), sonst gibt es wieder ein XML Objekt.
Hallo lokked

Steht dieser funktionierende Code nicht im Widerspruch zu Deiner Aussage?
Code:
write-output $opf.package.metadata.creator.'#text'

In diesem Element, was ist hier "hutzliputz"?
<dc:creator opf:file-as="Moorcock, Michael" opf:role="aut">Michael Moorcock</dc:creator>

Beste Grüsse
 
ral9004 schrieb:
Frage 1
Ich erhalte den Wert des Attributes "opf:role="aut", wenn ich mit "'#text' ergänze.
write-output $opf.package.metadata.creator.'#text'

Was bekommst du dann? Ich würde vermuten, du bekommst dann "Michael Moorcock"
Anhand deiner Screenshots ist schwer nachzuvollziehen, was du wann bekommst.

Und welche Property würdest du nehmen, um zu sagen "der Text des Tags"?
<tag text="hallo">welt</tag>

$tag.text => was ist das nun? (Spoiler: hallo, und $tag.'#text' => welt)
<tag #text="hallo">welt</tag>
dürfte kaum gültig sein.

Sorry, du hast mich ja gar nicht gefragt.
 
Zuletzt bearbeitet:
Beides ist gleich für die Ausgabe, weil die Attribute des Elements entweder explizit im Tag drin stehen oder als Unterelemente aufgeführt werden können. Wenn dein XML geparsed wird und dann in ein Objekt umgewandelt wird, werden beide als flache Attribute im Objekt angelegt.
Ich hab ja deine Datei nicht, also hab ich ein Beispiel für ein Attribut/Unterelement genommen (=Hutzliputz)
Aus dem Grund werden deine Attribute "file-as", "role" als Eigenschaften interpretiert und so im Objekt angelegt, die du direkt aufrufen kannst. #text ist ein pseudoattribut was für dich generiert wird, was sich auf den Inhalt des Tags bezieht.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: tollertyp
Die unterschiedliche Darstellung liegt an der XML-Struktur. Vermutlich hat das Element "creator" als einziges noch Attribute - hier "role" und "file-as". Wenn das zuerst ausgegeben wird, versucht PS das "tabellenartig" zu strukturieren und bleibt dann für den Rest der Ausgabe beim gleichen Schema. Bei den anderen Elementen findet er dann einfach keine Attribute und lässt die Spalte leer. Wird mit einem Tag ohne Attribute begonnen, erfolgt nur die Ausgabe des Wertes und auch diese Strukturierung wird dann beibehalten.

Ich überblicke die Spezifikation von opf nicht wirklich, deswegen kann ich dir nicht sagen, ob diese Attribute beim creator-Element vorhanden sein müssen oder nur vorhanden sein können. Wenn sie nur vorhanden sein können, wirst du wohl prüfen müssen, ob sie tatsächlich da sind.

Die Ausgabe des Autors mittels #text funktioniert bei mir reibungslos.

Code:
[xml] $foo = Get-Content .\test1.opf
$bar = $foo.package.metadata
Write-Output $bar.title
Write-Output $bar.creator.'#text'
Write-Output $bar.publisher
 
  • Gefällt mir
Reaktionen: ral9004
tollertyp schrieb:
Was bekommst du dann? Ich würde vermuten, du bekommst dann "Michael Moorcock"
Anhand deiner Screenshots ist schwer nachzuvollziehen, was du wann bekommst.

Und welche Property würdest du nehmen, um zu sagen "der Text des Tags"?
<tag text="hallo">welt</tag>

$tag.text => was ist das nun? (Spoiler: hallo, und $tag.'#text' => welt)
<tag #text="hallo">welt</tag>
dürfte kaum gültig sein.

Sorry, du hast mich ja gar nicht gefragt.
Hallo tollertyp

Wenn ich auf den Post eines Teilnehmers antworte spreche ich Ihn an. Was nicht heisst, dass nicht jeder Input willkommen ist. Wenn ich hierbei (informelle) Regeln verletze, einfach informieren. B.t.w. konnte ich in diesem Thread nicht erkennen, dass Du mich angesprochen hattest. Du hattest eine Auseinandersetzung mit dem TN "foobar"

A: Was mit .#Text erhalten
Ja - "Michsel Moorcock". Warum ist das so? Welche Regel steht dahinter?

B: Ohne .#Text
Wenn der Screenshot grösser sein soll oder ohne Dark Mode kann ich das gerne ändern.
Auf dem Screenshot sieht man, dass wenn "...metadata.title" ohne ".#Text" codiere, erhalte ich mit dem Output auch noch eine Headeline besteht aus den unterstrichenen Spaltentiteln "file-as" und "role" und #text
ps-xml-5.png


In der Specs steht nur
This specification adds to the creator element two optional attributes: role and file-as.

Meinem OPF File Beispiel
Code:
<dc:creator opf:file-as="Moorcock, Michael" opf:role="aut">Michael Moorcock</dc:creator>

D.h. das gemäss Specs der Inhalt des Elementes "creator" nur diese Angabe haben muss:
Code:
<dc:creator>Michael Moorcock</dc:creator>

Daraus leite ich ab, dass PS bei Verwendung von "package.metadata" mit dem Zusatz ".#text" nur den nicht optionalen Datenanteil liefert.

Leider liefert mir weder get-help noch die I-Net Suchmaschine eine klärende Info dazu

C: Zwei oder mehr Autoren

Wenn ein Buch zwei Autoren hat, sieht das Element "Creator" so aus:
Code:
<dc:creator opf:file-as="Aaker, Jennifer &amp; Bagdonas, Naomi" opf:role="aut">Jennifer Aaker</dc:creator>

Wenn ich hier die optionalen teile gemäss Specs weglasse, sehe ich dieses Element:
Code:
<dc:creator >Jennifer Aaker</dc:creator>

Welche Daten erhalte ich von Powershell for Windows (5.x)? Zwei Autoren in zwei Zeilen gelistet
ps-xml-6.png

Wenn der Screenshot zu klein ist, kann ich Ihn Dir extern verlinken.

Nochmals die gleiche Frage wie oben: Wo hat MS die Referenz für diese Logik betreffend PS for Windows und Namespaces hinterlegt?

Beste Grüsse
Ergänzung ()

lokked schrieb:
Beides ist gleich für die Ausgabe, weil die Attribute des Elements entweder explizit im Tag drin stehen oder als Unterelemente aufgeführt werden können. Wenn dein XML geparsed wird und dann in ein Objekt umgewandelt wird, werden beide als flache Attribute im Objekt angelegt.
lokked schrieb:
Beides ist gleich für die Ausgabe, weil die Attribute des Elements entweder explizit im Tag drin stehen oder als Unterelemente aufgeführt werden können. Wenn dein XML geparsed wird und dann in ein Objekt umgewandelt wird, werden beide als flache Attribute im Objekt angelegt.
Ich hab ja deine Datei nicht, also hab ich ein Beispiel für ein Attribut/Unterelement genommen (=Hutzliputz)
Aus dem Grund werden deine Attribute "file-as", "role" als Eigenschaften interpretiert und so im Objekt angelegt, die du direkt aufrufen kannst. #text ist ein pseudoattribut was für dich generiert wird, was sich auf den Inhalt des Tags bezieht.

Ich hab ja deine Datei nicht, also hab ich ein Beispiel für ein Attribut/Unterelement genommen (=Hutzliputz)
Aus dem Grund werden deine Attribute "file-as", "role" als Eigenschaften interpretiert und so im Objekt angelegt, die du direkt aufrufen kannst. #text ist ein pseudoattribut was für dich generiert wird, was sich auf den Inhalt des Tags bezieht.
Hallo lokked

Für mich als Fragesteller muss ich festhalten, dass Du dozierst und nicht auf meine konkreten Fragen eingehst.

Daten
Du fragst zum zweiten Mal nach Daten.
Es geht um dieses Element. Hier in zwei Beispielen:

Code:
<dc:creator opf:file-as="Moorcock, Michael" opf:role="aut">Michael Moorcock</dc:creator>

Code:
<dc:creator opf:file-as="Aaker, Jennifer &amp; Bagdonas, Naomi" opf:role="aut">Jennifer Aaker</dc:creator>

Auch habe ich in der Frage den Namespace angegeben:
Code:
<?xml version='1.0' encoding='utf-8'?>
<package xmlns="http://www.idpf.org/2007/opf" unique-identifier="uuid_id" version="2.0">
    <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">

Alle anderen Elemente in dieser .OPF Datei haben keinen Einfluss auf dieses Element bzw. die Ausgabe seiner Daten. Wie Du bestens weisst. Also verstehe ich Dich beim besten Willen nicht.

Theorie und Praxis
Deine Theorie:
Zitat von lokked:
Willst du nur den Wert eines bestimmtes Unterelements in der Ausgabe haben, musst du das auch direkt ansteuern indem du den Elementnamen an das jeweilige Elternelement anhängst
Code:
$opf.package.metadata.creator.hutzliputz
Ich habe Dich gebeten mir zu erklären, wie mein funktionierendes Beispiel zu Deiner Theorie passt
Code:
write-output $opf.package.metadata.creator.'#text'

Ich habe Beispiele für das Element von Anfang an gepostet. D.h. Du hättest einfach anhand dieser Daten Deinen Weg demonstrieren können.

Was machst Du? Produzierst wieder dieser unlesbaren, unformatierten akademischen Abgesang und gehst keinen einzigen Schritt auf meine Frage ein.

Bitte nicht als Angriff werten. Als Fragesteller bin ich der Kunde und gebe Dir Feedback zu Deinem Service. Ungefragt, aber nach zwei solchen Bleiwüsten auf Wolke Nummer 7 konnte ich mich nicht mehr bremsen...

Beste Grüsse
 
Zuletzt bearbeitet:
ral9004 schrieb:
Daraus leite ich ab, dass PS bei Verwendung von "package.metadata" mit dem Zusatz ".#text" nur den nicht optionalen Datenanteil liefert.
.#text liefert den Inhalt des Tags. Also das, was zwischen den "Klammern" steht. Ansonsten wird das komplette Element ausgegeben, einschließlich der Attribute. Was ist daran nicht verständlich und was hat bitte MS damit zu tun?
 
f00bar schrieb:
Die unterschiedliche Darstellung liegt an der XML-Struktur. Vermutlich hat das Element "creator" als einziges noch Attribute - hier "role" und "file-as". Wenn das zuerst ausgegeben wird, versucht PS das "tabellenartig" zu strukturieren und bleibt dann für den Rest der Ausgabe beim gleichen Schema. Bei den anderen Elementen findet er dann einfach keine Attribute und lässt die Spalte leer. Wird mit einem Tag ohne Attribute begonnen, erfolgt nur die Ausgabe des Wertes und auch diese Strukturierung wird dann beibehalten.

Ich überblicke die Spezifikation von opf nicht wirklich, deswegen kann ich dir nicht sagen, ob diese Attribute beim creator-Element vorhanden sein müssen oder nur vorhanden sein können. Wenn sie nur vorhanden sein können, wirst du wohl prüfen müssen, ob sie tatsächlich da sind.

Die Ausgabe des Autors mittels #text funktioniert bei mir reibungslos.

Code:
[xml] $foo = Get-Content .\test1.opf
$bar = $foo.package.metadata
Write-Output $bar.title
Write-Output $bar.creator.'#text'
Write-Output $bar.publisher
Hallo f00bar

Hattest Du Kenntnis von diesem "#.Text"?
Wenn ja, woher? Wie kann ich das wissen?

Ich habe zu diesem Punkt vorhin "toller Typ" eine ausführliche Frage gestellt.
D.h. die Spezifikation und was ich erhalte ergeben für mich keinen Sinn.

Wo ist das Tutorial von MS oder StackOverflow zu PS for Windows und Namespaces?
Mit praktischen Beispielen, Code Snippets, etc.

Wie im Post an "toller Typ" geschrieben habe, kann ein Buch mehrere Autoren haben. Das Element sieht dann so aus:
<dc:creator opf:file-as="Aaker, Jennifer &amp; Bagdonas, Naomi" opf:role="aut">Jennifer Aaker</dc:creator>

Mit meinem Code erhalte ich jeden Autor auf einer neuen Zeile:
Code:
[xml] $opf = gc .\metadata1.opf
write-output $opf.package.metadata.creator.'#text'
write-output $opf.package.metadata.title
write-output $opf.package.metadata.publisher

Obwohl ein Hauptautor im Element angegeben ist: "Jennifer Aaker"

D.h. ich muss bei der Abfrage dieser .OPF Datei berücksichtigen, dass "Creator" [n] Zeilen ausgiebt...

Nachdem ich so viele gute Tipps und Infos in diesem Thread erhalten habe, weiss ich nun das mein Fehler das Statment "return" war. Und der Rest werde ich nach Try and Error heraus finden...

Beste Grüsse
 
Na das freut uns aber, das doch noch was in deiner Gedankenwelt positiv aufgenommen worden ist
 
f00bar schrieb:
.#text liefert den Inhalt des Tags. Also das, was zwischen den "Klammern" steht. Ansonsten wird das komplette Element ausgegeben, einschließlich der Attribute. Was ist daran nicht verständlich und was hat bitte MS damit zu tun?
Hallo f00bar

Hier ist die Spezifikation:
https://idpf.org/epub/20/spec/OPF_2.0.1_draft.htm

Wenn mit CTRL-F nach "#text" suche finde ich nichts.

Microsoft hat in seiner Programmiersprache "Powershell for Windows" die Module für den Zugriff Daten in solchen Auszeichnungssprachen integriert. Da sollte doch eine Referenz zu erwarten sein?

Wenn ich auf beiden Seiten keine Infos erhalte, muss ich einfach auf die Geduld von Forumsteilnehmern hoffen.
Bzw. nach Try and Error mich durchkämpfen.

Beste Grüsse
 
PowerShell ist MS-typisch sehr gut dokumentiert. Das ersetzt aber kein XML-Basiswissen, denn genau das scheint dir irgendwie zu fehlen. Du musst ganz einfach wissen, was ein Element, ein Knoten, ein Attribut sind und wie XML überhaupt funktioniert. Wenn ich dir jetzt erzähle, dass "#text" einfach nur den tatsächlichen Inhalt eines Textnodes als String enthält, während der Text in XML selbst auch wieder ein Knoten ist, nutzt dir das irgendwas? Ich glaube kaum.

Ich kann mir irgendwie nicht vorstellen, dass dir eine Referenz wie diese irgendwie weiterhilft. Du bist es aber gewesen, der mit "#text" um die Ecke kam - da geht man als Leser einfach davon aus, dass du bestimmte Kenntnisse bereits hast. Wusstest du aber zum Beispiel, dass du anstatt "#text" auch ganz einfach .innerText verwenden könntest? Wenn nicht, kannst du auch das nicht MS in die Schuhe schieben.
 
  • Gefällt mir
Reaktionen: ral9004
Zurück
Oben