spsman
Goto Top

Powershell XML.SelectNodes findet nichts

Hi,

Ich bekomme aus einem Programm eine XML die ich gerne erweitern möchte. Undzwar möchte ich '<Symbol>' kopieren und dabei die <Component> OPN_SOLL mit V15_SOLL ersetzen.

Wenn ich jetzt jedoch '$sourceNode = $XMLContend.SelectNodes("//Parts")' ausführe ist $sourceNode.Count "0".

Wie kann ich auf 'Parts' Zugreifen und das Objekt Component kopieren/adressieren

Powershell:
Set-Location -path C:\XMLtest
$XMLContend = [XML](Get-Content ".\OPN_ORG.xml")  
$sourceNode = $XMLContend.SelectNodes("//Parts")  
$sourceNode.Count

XML:
opn_xml

Danke.

Content-ID: 1302715031

Url: https://administrator.de/contentid/1302715031

Ausgedruckt am: 19.12.2024 um 10:12 Uhr

149569
149569 26.09.2021 aktualisiert um 10:19:03 Uhr
Goto Top
XMLContend
Dazu sag ich jetzt mal nichts face-big-smile.

1. Von deiner XML sieht man leider nur die Hälfte und dann auch noch als Bild?? Warum kein richtiger Text?. Bei SelectNodes ist es aber essentiell wichtig wenn Namespaces vorhanden sind, und die kann man hier leider nicht erkennen wenn man nur die Hälfte da von sieht. Bei Namespaces muss man einen Namespace-Manger erstellen und diesem den Namespace in dem sich der Knoten befindet deklarieren. Alternativ nimmt man sich statt SelectNodes zu verwenden den Baum der Powershell Objekte her und itteriert darüber bsp.
$xmlContend."SW.Blocks.FC".Parts | %{
    $_
}
2. Das "Parts" scheint hier selber "reingeflickt" worden zu sein, denn die Elemente sind nicht in der richtigen Reihenfolge mit EndTags versehen, ungültiges XML bringt das dann ebenfalls zu Fall.

Danke.
Bitte.
colinardo
Lösung colinardo 26.09.2021 aktualisiert um 20:38:54 Uhr
Goto Top
Servus @SPSman,
@149569 hat schon einen wichtigen Hinweis gegeben. Wenn das XML-File Namespaces enthält muss man auch via Namespace-Prefix in der SelectNodes Methode arbeiten und einen Namespacemanager angeben in dem die Namespaces und dessen Prefixe enthalten sind.
Und wenn man genau auf das Bild schaut sieht man auch das es Namespaces enthält @149569, zwar nicht den Namespace an sich aber das xmlns reicht dann schon das zu behaupten face-wink.

screenshot

Hier mal ein Beispiel-XML File das eine dem Parts-Knoten übergeordnete Namespace Deklaration in dem Knoten
<FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v1">
enthält:

<?xml version="1.0" encoding="utf-8"?>  
<Document>
	<SW.Blocks.CompileUnit ID="3" CompositionName="CompileUnits">  
		<AttributeList>
			<NetworkSource>
				<FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v1">  
					<Parts>
						<Access Scope="LocalVariable" UId="21">  
							<Symbol>
								<Component Name="bInCondition" />  
								<Component Name="OPN_SOLL" />  
							</Symbol>
						</Access>
						<Access Scope="LocalVariable" UId="22">  
							<Symbol>
								<Component Name="bOutDoSomething" />  
							</Symbol>
						</Access>
						<Part Name="Contact" UId="23" />  
						<Part Name="Coil" UId="24" />  
					</Parts>
					<Wires>
						<Wire UId="25">  
							<Powerrail />
							<NameCon UId="23" Name="in" />  
						</Wire>
						<Wire UId="26">  
							<IdentCon UId="21" />  
							<NameCon UId="23" Name="operand" />  
						</Wire>
						<Wire UId="27">  
							<NameCon UId="23" Name="out" />  
							<NameCon UId="24" Name="in" />  
						</Wire>
						<Wire UId="28">  
							<IdentCon UId="22" />  
							<NameCon UId="24" Name="operand" />  
						</Wire>
					</Wires>
				</FlgNet>
			</NetworkSource>
			<ProgrammingLanguage>LAD</ProgrammingLanguage>
		</AttributeList>
		<ObjectList>
			<MultilingualText ID="4" CompositionName="Comment">  
				<ObjectList>
					<MultilingualTextItem ID="5" CompositionName="Items">  
						<AttributeList>
							<Culture>en-US</Culture>
							<Text>This network uses an input condition to activate an output action</Text>
						</AttributeList>
					</MultilingualTextItem>
				</ObjectList>
			</MultilingualText>
			<MultilingualText ID="6" CompositionName="Title">  
				<ObjectList>
					<MultilingualTextItem ID="7" CompositionName="Items">  
						<AttributeList>
							<Culture>en-US</Culture>
							<Text>Simple contact/coil network</Text>
						</AttributeList>
					</MultilingualTextItem>
				</ObjectList>
			</MultilingualText>
		</ObjectList>
	</SW.Blocks.CompileUnit>
</Document>

Darauf aubauend nun ein Skript das die Namespaces via Namespace-Manager bekannt macht und dann diesen in der SelectNodes Methode nutzt.:
Bei der folgenden Methode extrahiere ich alle enthaltenen Namespaces automatisch, du kannst diese aber auch manuell dem NamespaceManger hinzufügen via
$ns.AddNamespace("prefix","namespace-uri")
# xml Objekt erstellen
$xml = New-Object XML
# XML Dokument laden
$xml.Load('D:\spsman\demo.xml')  

# NamespaceManager erstellen
[System.Xml.XmlNamespaceManager]$ns = new-Object System.Xml.XmlNamespaceManager $xml.NameTable
# Extrahiere alle Namespaces und fürge diese dem Namespacemanager-Objekt hinzu
$xml.SelectNodes('//*') | ?{$_.NamespaceURI -ne ''} | select @{n='Prefix';e={$_.GetPrefixOfNamespace($_.NamespaceURI)}},NamespaceURI | select Prefix,NamespaceURI -unique | %{if($_.Prefix -eq ''){$_.Prefix = 'default'};$ns.AddNamespace($_.Prefix,$_.NamespaceURI)}  
# Abfrage
$nodes = $xml.SelectNodes("//default:Parts//default:Component[@Name='OPN_SOLL']",$ns)  

$nodes | %{
    # Klone Knoten
    $new = $_.Clone()
    # setze Name Attribut auf neuen Wert
    $new.SetAttribute("Name","V15_SOLL")  
    # hänge neuen Knoten am parent Knoten an
    [void]$_.parentNode.appendChild($new)
}

# speichere
$xml.Save('D:\spsman\demo_out.xml')  

Das Ergebnis des Codes macht aus dem Abschnitt:
<Symbol>
    <Component Name="bInCondition" />  
    <Component Name="OPN_SOLL" />  
</Symbol>
dann diesen (du wolltest ja kopieren und dabei anpassen und nicht nur ersetzen, so jedenfalls habe ich deinen Text interpretiert)
<Symbol>
    <Component Name="bInCondition" />  
    <Component Name="OPN_SOLL" />  
    <Component Name="V15_SOLL" />  
</Symbol>
Willst du stattdessen den Knoten nur ändern und nicht kopieren dann reicht es den Code der Schleife oben so abzuändern
# ...
$nodes | %{
    $_.SetAttribute("Name","V15_SOLL")  
}
# ....
Ergebnis ist dann...
<Symbol>
    <Component Name="bInCondition" />  
    <Component Name="V15_SOLL" />  
</Symbol>

Hier auch noch etwas Lektüre zum nachlesen
https://www.windowspro.de/script/xml-powershell-xpath-abfragen-namespace ...

Grüße Uwe
SPSman
SPSman 26.09.2021 um 20:09:50 Uhr
Goto Top
Hi,
hier mal die komplett XML:

<?xml version="1.0" encoding="utf-8"?>  
<Document>
  <Engineering version="V16" />  
  <DocumentInfo>
    <Created>2021-09-24T12:05:38.6575083Z</Created>
    <ExportSetting>WithDefaults, WithReadOnly</ExportSetting>
    <InstalledProducts>
      <Product>
        <DisplayName>Totally Integrated Automation Portal</DisplayName>
        <DisplayVersion>V16 Update 4</DisplayVersion>
      </Product>
      <OptionPackage>
        <DisplayName>TIA Portal Version Control Interface</DisplayName>
        <DisplayVersion>V16 Update 2</DisplayVersion>
      </OptionPackage>
      <OptionPackage>
        <DisplayName>TIA Portal Openness</DisplayName>
        <DisplayVersion>V16 Update 4</DisplayVersion>
      </OptionPackage>
      <Product>
        <DisplayName>STEP 7 Professional</DisplayName>
        <DisplayVersion>V16 Update 4</DisplayVersion>
      </Product>
      <OptionPackage>
        <DisplayName>STEP 7 Safety</DisplayName>
        <DisplayVersion>V16</DisplayVersion>
      </OptionPackage>
      <Product>
        <DisplayName>WinCC Advanced</DisplayName>
        <DisplayVersion>V16 Update 4</DisplayVersion>
      </Product>
    </InstalledProducts>
  </DocumentInfo>
  <SW.Blocks.FC ID="0">  
    <AttributeList>
      <AutoNumber>false</AutoNumber>
      <CodeModifiedDate ReadOnly="true">2021-09-24T12:05:29.1050613Z</CodeModifiedDate>  
      <CompileDate ReadOnly="true">2021-09-24T12:05:29.1135696Z</CompileDate>  
      <CreationDate ReadOnly="true">2020-02-24T14:45:27.4460864Z</CreationDate>  
      <HandleErrorsWithinBlock ReadOnly="true">false</HandleErrorsWithinBlock>  
      <HeaderAuthor>P-MONTAN</HeaderAuthor>
      <HeaderFamily />
      <HeaderName />
      <HeaderVersion>1.0</HeaderVersion>
      <Interface><Sections xmlns="http://www.siemens.com/automation/Openness/SW/Interface/v4">  
  <Section Name="Input" />  
  <Section Name="Output" />  
  <Section Name="InOut" />  
  <Section Name="Temp" />  
  <Section Name="Constant" />  
  <Section Name="Return">  
    <Member Name="Ret_Val" Datatype="Void" Accessibility="Public" />  
  </Section>
</Sections></Interface>
      <InterfaceModifiedDate ReadOnly="true">2016-08-12T11:16:53.3236502Z</InterfaceModifiedDate>  
      <IsConsistent ReadOnly="true">true</IsConsistent>  
      <IsIECCheckEnabled>false</IsIECCheckEnabled>
      <IsKnowHowProtected ReadOnly="true">false</IsKnowHowProtected>  
      <IsWriteProtected ReadOnly="true">false</IsWriteProtected>  
      <LibraryConformanceStatus ReadOnly="true">Fehler: Der Baustein enthält Aufrufe von Einzelinstanzen.  
Warnung: Das Objekt enthält Zugriffe auf globale Datenbausteine.
</LibraryConformanceStatus>
      <MemoryLayout>Standard</MemoryLayout>
      <ModifiedDate ReadOnly="true">2021-09-24T12:05:29.1050613Z</ModifiedDate>  
      <Name>015_Ventile und Klappen</Name>
      <Number>15</Number>
      <ParameterModified ReadOnly="true">2016-08-12T11:16:53.3236502Z</ParameterModified>  
      <PLCSimAdvancedSupport ReadOnly="true">true</PLCSimAdvancedSupport>  
      <ProgrammingLanguage>FBD</ProgrammingLanguage>
      <SetENOAutomatically>false</SetENOAutomatically>
      <StructureModified ReadOnly="true">2016-08-12T11:16:53.3236502Z</StructureModified>  
      <UDABlockProperties />
      <UDAEnableTagReadback>false</UDAEnableTagReadback>
    </AttributeList>
    <ObjectList>
      <MultilingualText ID="1" CompositionName="Comment">  
        <ObjectList>
          <MultilingualTextItem ID="2" CompositionName="Items">  
            <AttributeList>
              <Culture>de-DE</Culture>
              <Text />
            </AttributeList>
          </MultilingualTextItem>
          <MultilingualTextItem ID="3" CompositionName="Items">  
            <AttributeList>
              <Culture>en-GB</Culture>
              <Text />
            </AttributeList>
          </MultilingualTextItem>
        </ObjectList>
      </MultilingualText>
      <SW.Blocks.CompileUnit ID="4" CompositionName="CompileUnits">  
        <AttributeList>
          <NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">  
  <Parts>
    <Access Scope="GlobalVariable" UId="21">  
      <Symbol>
        <Component Name="004_Rech" />  
        <Component Name="OPN_SOLL" />  
        <Address Area="DB" Type="Real" BlockNumber="4" BitOffset="32" Informative="true" />  
      </Symbol>
    </Access>
    <Access Scope="TypedConstant" UId="22">  
      <Constant>
        <ConstantValue>T#30s</ConstantValue>
        <StringAttribute Name="Format" Informative="true">Time</StringAttribute>  
        <StringAttribute Name="FormatFlags" Informative="true">TypeQualifier</StringAttribute>  
      </Constant>
    </Access>
    <Access Scope="GlobalVariable" UId="23">  
      <Symbol>
        <Component Name="030_Dat" />  
        <Component Name="OPN" />  
        <Address Area="DB" Type="UDT_AUMA_AC012" BlockNumber="30" BitOffset="496" Informative="true" />  
      </Symbol>
    </Access>
    <Call UId="24">  
      <CallInfo Name="AUMA AC01.2" BlockType="FB">  
        <IntegerAttribute Name="BlockNumber" Informative="true">160</IntegerAttribute>  
        <DateAttribute Name="ParameterModifiedTS" Informative="true">2020-03-24T15:03:20</DateAttribute>  
        <Instance Scope="GlobalVariable" UId="25">  
          <Component Name="IDB_OPN" />  
          <Address Area="DB" Type="AUMA AC01.2" BlockNumber="1000" BitOffset="0" Informative="true" />  
        </Instance>
        <Parameter Name="HW_In" Section="Input" Type="HW_IO">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="HW_Out" Section="Input" Type="HW_IO">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Bedienung" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Netz_ok" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Not_Zu" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Not_Auf" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Ext_Hand" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Ext_Auto" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Ext_Reset" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="ST_ext" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="BF_Zu" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="BF_Auf" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="BF_Soll" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Soll" Section="Input" Type="Real">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Auto_Quit" Section="Input" Type="Bool">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="T_EL" Section="Input" Type="Time">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
        <Parameter Name="Daten" Section="InOut" Type="&quot;UDT_AUMA_AC012&quot;">  
          <StringAttribute Name="InterfaceFlags" Informative="true">S7_Visible</StringAttribute>  
        </Parameter>
      </CallInfo>
    </Call>
  </Parts>
  <Wires>
    <Wire UId="41">  
      <OpenCon UId="26" />  
      <NameCon UId="24" Name="en" />  
    </Wire>
    <Wire UId="42">  
      <OpenCon UId="27" />  
      <NameCon UId="24" Name="HW_In" />  
    </Wire>
    <Wire UId="43">  
      <OpenCon UId="28" />  
      <NameCon UId="24" Name="HW_Out" />  
    </Wire>
    <Wire UId="44">  
      <OpenCon UId="29" />  
      <NameCon UId="24" Name="Bedienung" />  
    </Wire>
    <Wire UId="45">  
      <OpenCon UId="30" />  
      <NameCon UId="24" Name="Netz_ok" />  
    </Wire>
    <Wire UId="46">  
      <OpenCon UId="31" />  
      <NameCon UId="24" Name="Not_Zu" />  
    </Wire>
    <Wire UId="47">  
      <OpenCon UId="32" />  
      <NameCon UId="24" Name="Not_Auf" />  
    </Wire>
    <Wire UId="48">  
      <OpenCon UId="33" />  
      <NameCon UId="24" Name="Ext_Hand" />  
    </Wire>
    <Wire UId="49">  
      <OpenCon UId="34" />  
      <NameCon UId="24" Name="Ext_Auto" />  
    </Wire>
    <Wire UId="50">  
      <OpenCon UId="35" />  
      <NameCon UId="24" Name="Ext_Reset" />  
    </Wire>
    <Wire UId="51">  
      <OpenCon UId="36" />  
      <NameCon UId="24" Name="ST_ext" />  
    </Wire>
    <Wire UId="52">  
      <OpenCon UId="37" />  
      <NameCon UId="24" Name="BF_Zu" />  
    </Wire>
    <Wire UId="53">  
      <OpenCon UId="38" />  
      <NameCon UId="24" Name="BF_Auf" />  
    </Wire>
    <Wire UId="54">  
      <OpenCon UId="39" />  
      <NameCon UId="24" Name="BF_Soll" />  
    </Wire>
    <Wire UId="55">  
      <IdentCon UId="21" />  
      <NameCon UId="24" Name="Soll" />  
    </Wire>
    <Wire UId="56">  
      <OpenCon UId="40" />  
      <NameCon UId="24" Name="Auto_Quit" />  
    </Wire>
    <Wire UId="57">  
      <IdentCon UId="22" />  
      <NameCon UId="24" Name="T_EL" />  
    </Wire>
    <Wire UId="58">  
      <IdentCon UId="23" />  
      <NameCon UId="24" Name="Daten" />  
    </Wire>
  </Wires>
</FlgNet></NetworkSource>
          <ProgrammingLanguage>FBD</ProgrammingLanguage>
        </AttributeList>
        <ObjectList>
          <MultilingualText ID="5" CompositionName="Comment">  
            <ObjectList>
              <MultilingualTextItem ID="6" CompositionName="Items">  
                <AttributeList>
                  <Culture>de-DE</Culture>
                  <Text>-Nix-</Text>
                </AttributeList>
              </MultilingualTextItem>
              <MultilingualTextItem ID="7" CompositionName="Items">  
                <AttributeList>
                  <Culture>en-GB</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
          <MultilingualText ID="8" CompositionName="Title">  
            <ObjectList>
              <MultilingualTextItem ID="9" CompositionName="Items">  
                <AttributeList>
                  <Culture>de-DE</Culture>
                  <Text>ANLGAE OPN NW_KOMMENTAR</Text>
                </AttributeList>
              </MultilingualTextItem>
              <MultilingualTextItem ID="A" CompositionName="Items">  
                <AttributeList>
                  <Culture>en-GB</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <SW.Blocks.CompileUnit ID="B" CompositionName="CompileUnits">  
        <AttributeList>
          <NetworkSource />
          <ProgrammingLanguage>FBD</ProgrammingLanguage>
        </AttributeList>
        <ObjectList>
          <MultilingualText ID="C" CompositionName="Comment">  
            <ObjectList>
              <MultilingualTextItem ID="D" CompositionName="Items">  
                <AttributeList>
                  <Culture>de-DE</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
              <MultilingualTextItem ID="E" CompositionName="Items">  
                <AttributeList>
                  <Culture>en-GB</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
          <MultilingualText ID="F" CompositionName="Title">  
            <ObjectList>
              <MultilingualTextItem ID="10" CompositionName="Items">  
                <AttributeList>
                  <Culture>de-DE</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
              <MultilingualTextItem ID="11" CompositionName="Items">  
                <AttributeList>
                  <Culture>en-GB</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <MultilingualText ID="12" CompositionName="Title">  
        <ObjectList>
          <MultilingualTextItem ID="13" CompositionName="Items">  
            <AttributeList>
              <Culture>de-DE</Culture>
              <Text>Ansteuerung der einzelnen Ventile und Klappen überwachen.</Text>
            </AttributeList>
          </MultilingualTextItem>
          <MultilingualTextItem ID="14" CompositionName="Items">  
            <AttributeList>
              <Culture>en-GB</Culture>
              <Text />
            </AttributeList>
          </MultilingualTextItem>
        </ObjectList>
      </MultilingualText>
    </ObjectList>
  </SW.Blocks.FC>
</Document>

mit dem Thema Namespaces habe ich mich noch nicht beschäftigt. Werde ich wohl noch müssen. Das "Parts" ist jedoch nicht "hineingefirmelt" sondern genau so aus dem Siemens Programm gekommen ;)

VG Rob
149569
149569 26.09.2021 aktualisiert um 20:49:46 Uhr
Goto Top
Zitat von @SPSman:


mit dem Thema Namespaces habe ich mich noch nicht beschäftigt. Werde ich wohl noch müssen. Das "Parts" ist jedoch nicht "hineingefirmelt" sondern genau so aus dem Siemens Programm gekommen ;)

VG Rob

Na dann hat @colinardo es dir ja schon auf den Silbertablett serviert.
SPSman
SPSman 27.09.2021 aktualisiert um 14:44:08 Uhr
Goto Top
Zitat von @colinardo:

Servus @SPSman,
Grüße Uwe

Hallo Uwe,

ich habe dein Script mal ausprobiert und es passt nachtürlich super zu meiner Aufgabenstellung.
Ich versuche ja immer ein einfaches Beispiel zu nehmen, das zu verstehen und dann komplexere Aufgagen zu erledigen...


Tja jetzt habe ich versuch dein Script anzupassen und es kommt nur murcks :S.


Mein Script:

# xml Objekt erstellen
$xml = New-Object XML
# XML Dokument laden
$xml.Load('D:\spsman\demo.xml')  

# NamespaceManager erstellen
[System.Xml.XmlNamespaceManager]$ns = new-Object System.Xml.XmlNamespaceManager $xml.NameTable
# Extrahiere alle Namespaces und fürge diese dem Namespacemanager-Objekt hinzu
$xml.SelectNodes('//*') | ?{$_.NamespaceURI -ne ''} | select @{n='Prefix';e={$_.GetPrefixOfNamespace($_.NamespaceURI)}},NamespaceURI | select Prefix,NamespaceURI -unique | %{if($_.Prefix -eq ''){$_.Prefix = 'default'};$ns.AddNamespace($_.Prefix,$_.NamespaceURI)}  
# Abfrage
$nodes = $xml.SelectSingleNode("//default:'SW.Blocks.CompileUnit'",$ns)  


$nodes.Count
$z=0

foreach($node in $nodes)
{
$z+=1
$z
$node
}

Ausgabe:
PS C:\Mailbox\01_Projekte\Roskow\OPN_2> C:\Mailbox\01_Projekte\Roskow\FC_erweitern.ps1
Ausnahme beim Aufrufen von "SelectSingleNode" mit 2 Argument(en): "'default:'SW.Blocks.CompileUnit'' > hat einen ungültig gekennzeichneten Namen."
In C:\Mailbox\01_Projekte\Roskow\FC_erweitern.ps1:12 Zeichen:1
+$nodes = $xml.SelectSingleNode("
default:'SW.Blocks.CompileUnit'",$n ...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (face-smile , MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

2

1
2

Er hat trotz "SelectsingleNote" 2 objekte. Warum?
Und was für ein Problem er mit der Fehlermeldung meint ist mit auch noch Schleierhaft.

Die Gesamte Aufgabenstellung ist eigentlich erste SW.Blocks.CompileUnit kopieren, ID durch Laufvariable ergänzen und Textelement, OPN , ANLAGE , NW_KOMMENTAR durch die Entsprechenden Arraystrings ersetzen. (Als es wird 3 Arrays mit den entsprechenden Ersatzstrings geben.)


Zu verändernde Stellen(Zeile 1,8,6,46):
     <SW.Blocks.CompileUnit ID="**4**" CompositionName="CompileUnits">  
        <AttributeList>
          <NetworkSource>
<Parts>
    <Access Scope="GlobalVariable" UId="21">  
      <Symbol>

        <Component Name="**OPN_SOLL**" />  
        <Address Area="DB" Type="Real" BlockNumber="4" BitOffset="32" Informative="true" />  
      </Symbol>
    </Access>
  ...
    <Access Scope="GlobalVariable" UId="23">  
      <Symbol>
        <Component Name="030_Dat" />  
        <Component Name="OPN" />  
        <Address Area="DB" Type="UDT_AUMA_AC012" BlockNumber="30" BitOffset="496" Informative="true" />  
      </Symbol>
    </Access>
...
</Parts>
...

<ObjectList>
          <MultilingualText ID="5" CompositionName="Comment">  
            <ObjectList>
              <MultilingualTextItem ID="6" CompositionName="Items">  
                <AttributeList>
                  <Culture>de-DE</Culture>
                  <Text>-Nix-</Text>
                </AttributeList>
              </MultilingualTextItem>
              <MultilingualTextItem ID="7" CompositionName="Items">  
                <AttributeList>
                  <Culture>en-GB</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
          <MultilingualText ID="8" CompositionName="Title">  
            <ObjectList>
              <MultilingualTextItem ID="9" CompositionName="Items">  
                <AttributeList>
                  <Culture>de-DE</Culture>
                  <Text>**ANLGAE OPN NW_KOMMENTAR**</Text>
                </AttributeList>
              </MultilingualTextItem>
              <MultilingualTextItem ID="A" CompositionName="Items">  
                <AttributeList>
                  <Culture>en-GB</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
        </ObjectList>
colinardo
colinardo 27.09.2021 aktualisiert um 15:38:08 Uhr
Goto Top
Zitat von @SPSman:
Und was für ein Problem er mit der Fehlermeldung meint ist mit auch noch Schleierhaft.
1. Du setzt den Knotennamen in der XPath Query in Hochkommas, das ist falsch, das brauchst du hier verwechselst hier Powershell mit XPath Syntax.

2. Bei dem Knoten "SW.Blocks.CompileUnit" brauchst du keinen Namespacemanager, da dieser Knoten nicht unterhalb der Baumstruktur liegt welcher den Namespace definiert! Für die XPath Abfrage brauchen wir also den Namespacemanger nur wenn wir Knoten selektieren wollen die in einer Namespace definition, das ist bei deiner Aufgabenstellung nur für den Component Knoten mit dem Attribute Name="OPN_SOLL" der Fall.

screenshot


Er hat trotz "SelectsingleNote" 2 objekte. Warum?
3. Das du noch 2 Objekte in der Variablen hast liegt daran das du diese wohl in der ISE vorher mal gefüllt hast und diese immer noch alten Inhalt ausgibt.

Dein Vorhaben sieht dann so aus (eine Stelle die du definiert hast finde ich zwar nicht aber das solltest du dann selber sehen). In die Werte habe ich nur durch Demo-Text gesetzt, das kannst du dann durch den Inhalt deiner Array-Werte ersetzen.

# xml Objekt erstellen
$xml = New-Object XML
# xml laden
$xml.Load('D:\spsman\demo.xml')  

# NamespaceManager erstellen
[System.Xml.XmlNamespaceManager]$ns = new-Object System.Xml.XmlNamespaceManager $xml.NameTable
# Extract all used Namespaces in XML document and them to NamespaceManager
$xml.SelectNodes('//*') | ?{$_.NamespaceURI -ne ''} | select @{n='Prefix';e={$_.GetPrefixOfNamespace($_.NamespaceURI)}},NamespaceURI | select Prefix,NamespaceURI -unique | %{if($_.Prefix -eq ''){$_.Prefix = 'default'};$ns.AddNamespace($_.Prefix,$_.NamespaceURI)}  

# Abfrage des ersten 'SW.Blocks.CompileUnit' Knotens 
$node = $xml.SelectSingleNode("//SW.Blocks.CompileUnit")  
# abbrechen wenn kein Knoten gefunden wurde.
if (!$node){
    throw "Error, 'SW.Blocks.CompileUnit' Node not found!"  
    exit 1
}
# erstelle eine Kopie des Knotens im Speicher
$newnode = $node.Clone()
# id anpassen
$newnode.Id = "100"  
# OPN anpassen
$newnode.SelectNodes("//default:Component[@Name='OPN_SOLL']",$ns) | %{$_.setAttribute('Name','V15_SOLL')}  
# NW_KOMMENTAR anpassen
$newnode.SelectSingleNode("//ObjectList/MultilingualText[@CompositionName='Title']//AttributeList[Culture='de-DE']/Text") | %{$_.innerText = "Whatever"}  
# hänge den kopierten Knoten im selben Parent wie vom Original wieder ins XML ein
[void]$node.ParentNode.AppendChild($newNode)
# speichere das geänderte xml unter neuem Namen
$xml.Save('D:\spsman\demo_out.xml')  

Alternativ kannst du Knoten auch wenn die Position im Baum fest ist auch ohne XPath Selection ansprechen, bspw. für die Variable $node in obigem Skript sähe das dann so aus um den ersten 'SW.Blocks.CompileUnit' Knoten zu bekommen
$node = $xml.Document.'SW.Blocks.FC'.ObjectList.'SW.Blocks.CompileUnit'
das ist aber nur zuverlässig wenn du 100% sagen kannst das dieser Knoten immer an genau dieser Baumstruktur platziert ist.

Grüße Uwe
SPSman
SPSman 28.09.2021 um 09:44:28 Uhr
Goto Top
Hallo Uwe,

erstmal vielen Dank für dein Script.

Ich habe es erweitert, aber natürlich funktionieren viele Sagen noch nicht.

" <Component Name="OPN" />" wird nicht angepasst bzw. selectnodes läuft mal wieder ins leere..

Dann muss der Bereich hinter SW.Blocks.CompileUnitauch wieder dahinter eingefügt werden

Und ALLE "ID"(nicht Uid) Atribute müssen verändert werden.

Ich hab sowas zwar schonmal mit VBS und Suchen/ersetzen gebaut, allerdings will ich ja gerade XML lernen.

Es sollen alle Attribute die "OPN*" im Namen enthalten durch eine String Variable ersetzt werden.
Ebenfalls sollen auch alle IDs mittels Laufvariable verändert werden. (das geht vermutlich gut mit Getattribute und Setattribute)

Wie kann ich alle Nodes im $NewNode die den String "OPN"(also Sowohl "OPN" als auch "OPN_Soll" oder "OPN bla") adressieren?
Wie Kann ich alle Nodes im $NewNode die eine "ID" haben heraussuchen?
Wieso $Temp_Kommentar nicht geschrieben?


Aktuelle Stand:
#Array Objektname
$ObjName=('V15','M18')  
$ObjKommentar=('Ventil 15','Motor 18')  
$ObjAnlage=('Bypas','Pumpenraum')  
$OPN_in ='D:\spsman\OPN_ORG.xml'  
$OPN_Out='D:\spsman\OPN_OUT.xml'  

# xml Objekt erstellen
$xml = New-Object XML
# xml laden
$xml.Load($OPN_in)

$Urxml = $xml.Clone()



# NamespaceManager erstellen
[System.Xml.XmlNamespaceManager]$ns = new-Object System.Xml.XmlNamespaceManager $xml.NameTable
# Extract all used Namespaces in XML document and them to NamespaceManager
$xml.SelectNodes('//*') | ?{$_.NamespaceURI -ne ''} | select @{n='Prefix';e={$_.GetPrefixOfNamespace($_.NamespaceURI)}},NamespaceURI | select Prefix,NamespaceURI -unique | %{if($_.Prefix -eq ''){$_.Prefix = 'default'};$ns.AddNamespace($_.Prefix,$_.NamespaceURI)}  




# Abfrage des ersten 'SW.Blocks.CompileUnit' Knotens 
$Urnode = $xml.SelectSingleNode("//SW.Blocks.CompileUnit")  
# abbrechen wenn kein Knoten gefunden wurde.
if (!$Urnode){
    throw "Error, 'SW.Blocks.CompileUnit' Node not found!"  
    exit 1
}
$z=0
foreach($Obj in $objName)
{
# erstelle eine Kopie des Knotens im Speicher
$newnode = $Urnode.Clone()
# OPN_soll anpassen
$newnode.SelectNodes("//default:Component[@Name='OPN_SOLL']",$ns) | %{$_.setAttribute('Name',$Obj+'_Soll')}#< geht  
# OPN Anpassen
$newnode.SelectNodes("//default:Compnent[@Name='OPN']",$ns) | %{$_.SetAttribute('Name',$Obj+" ")}#< geht nicht  

# NW_KOMMENTAR einfügen
#$newnode.SelectSingleNode("//ObjectList/MultilingualText[@CompositionName='Title']//AttributeList[Culture='de-DE']/Text") | %{$_.innerText = "Whatever"} 
[string]$Temp_Kommentar= '"'+$ObjAnlage[$z]+" "+$ObjName[$z]+" "+$ObjKommentar[$z]+'"'  
$Temp_Kommentar
$newnode.SelectSingleNode("//ObjectList/MultilingualText[@CompositionName='Title']//AttributeList[Culture='de-DE']/Text") | %{$_.innerText = $Temp_Komentar+""}#< geht nicht  


$z+=1
# id anpassen
$newnode.Id = (100*$z).ToString()


$IDNodes=$newnode.SelectNodes("//*")  
#$IDNodes

# hänge den kopierten Knoten im selben Parent wie vom Original wieder ins XML ein
[void]$Urnode.ParentNode.AppendChild($newNode)

}
#Abschluss Node erhalten
$EndNode= $Urxml.SelectNodes("/Document/SW.Blocks.FC/ObjectList/MultilingualText[@CompositionName='Title']")  
$EndNode
#Abschluss Node anfügen
[void]$Urnode.ParentNode.AppendChild($EndNode)#<geht nicht


# speichere das geänderte xml unter neuem Namen
$xml.Save($OPN_Out)
colinardo
colinardo 28.09.2021 aktualisiert um 11:18:46 Uhr
Goto Top
Servus again.
Zitat von @SPSman:
" <Component Name="OPN" />" wird nicht angepasst bzw. selectnodes läuft mal wieder ins leere..
War ja auch keine Anforderung deinerseits oben, da war die Rede von "OPN_SOLL".

Dann muss der Bereich hinter SW.Blocks.CompileUnitauch wieder dahinter eingefügt werden
Macht mein Skript mit deinem oben geposteten XML einwandfrei.

Und ALLE "ID"(nicht Uid) Atribute müssen verändert werden.

Kannst du leicht addressieren
$xml.SelectNodes("//*[@ID]")  

Es sollen alle Attribute die "OPN*" im Namen enthalten durch eine String Variable ersetzt werden.
Wie kann ich alle Nodes im $NewNode die den String "OPN"(also Sowohl "OPN" als auch "OPN_Soll" oder "OPN bla") adressieren?
Select sieht dann so aus
$xml.SelectNodes("//*[contains(@*,'OPN')]")  

Wie Kann ich alle Nodes im $NewNode die eine "ID" haben heraussuchen?
s. oben.
Wieso $Temp_Kommentar nicht geschrieben?
Tippfehler der Variable $Temp_Komentar statt $Temp_Kommentar

$newnode.SelectNodes("//default:**Compnent**[@Name='OPN']",$ns) | %{$_.SetAttribute('Name',$Obj+" ")}#< geht nicht

Man sollte vorher nochmal Korrektur lesen, erneuter Tippfehler ... Compnent

Ich bin jetzt raus. Da kommt man sich hier doch ehrlich gesagt langsam aber sicher veralbert vor wenn man hier alles schnell mal einkippt bevor man es überhaupt Korrektur gelesen hat ... face-sad.

Bitte lies dir zur XPATH-Selections Syntax die einschlägigen Dokumentationen durch und übe damit sonst lernst du aus dem ganzen hier nichts.
https://www.w3schools.com/xml/xpath_syntax.asp

Und vor allem, mehr Präzision an den Tag legen!

Viel Erfolg.

Grüße Uwe

p.s. Das ursprüngliche Problem dieses Threads wurde gelöst, alles andere ist jetzt Off-Topic und kannst du dir gerne per PN von mir ein Angebot für weitere Arbeiten einholen!
Den Beitrag also bitte noch auf gelöst setzen, und Lösungen markieren. Merci.
148656
148656 28.09.2021 um 10:47:38 Uhr
Goto Top
Zitat von @colinardo:
...
Ich bin jetzt raus. Da kommt man sich hier doch ehrlich gesagt langsam aber sicher veralbert vor wenn man hier alles schnell mal einkippt bevor man es überhaupt Korrektur gelesen hat ... face-sad.

Das Problem, kann man mit Python lösen.
Monty Python face-big-smile

SPSman
SPSman 28.09.2021 aktualisiert um 12:42:12 Uhr
Goto Top
Zitat von @colinardo:

Servus again.
Zitat von @SPSman:
" <Component Name="OPN" />" wird nicht angepasst bzw. selectnodes läuft mal wieder ins leere..
War ja auch keine Anforderung deinerseits oben, da war die Rede von "OPN_SOLL".
Das ist nicht Korrekt. Oben schrieb ich Zeile 8 und Zeile 16 soll verändert werden. (OPN_SOLL und OPN)


Dann muss der Bereich hinter SW.Blocks.CompileUnitauch wieder dahinter eingefügt werden
Macht mein Skript mit deinem oben geposteten XML einwandfrei.
-> Leider nicht da MultilingualText auf der Gleichen ebene wie SW.Blocks.CompileUnit werden die neuen SW.Blocks.CompileUnit Objekte hinten angehängt

Und ALLE "ID"(nicht Uid) Atribute müssen verändert werden.
Habe ich Gestern erst herausgefunden.


Kannst du leicht addressieren
> $xml.SelectNodes("//*[@ID]")  
> 
Danke, Test folgt.
Es sollen alle Attribute die "OPN*" im Namen enthalten durch eine String Variable ersetzt werden.
Wie kann ich alle Nodes im $NewNode die den String "OPN"(also Sowohl "OPN" als auch "OPN_Soll" oder "OPN bla") adressieren?
Select sieht dann so aus
> $xml.SelectNodes("//*[contains(@*,'OPN')]")  
> 
Danke, Test folgt.

Wieso $Temp_Kommentar nicht geschrieben?
Tippfehler der Variable $Temp_Komentar statt $Temp_Kommentar
Oh man, ja das hätte mir auch auffallen sollen!
Man sollte vorher nochmal Korrektur lesen, erneuter Tippfehler ... Compnent
Danke. Nehme Ich mir zu Herzen
Ich bin jetzt raus. Da kommt man sich hier doch ehrlich gesagt langsam aber sicher veralbert vor wenn man hier alles schnell mal einkippt bevor man es überhaupt Korrektur gelesen hat ... face-sad.

Das tut mir leid, es war keine Absicht.


Bitte lies dir zur XPATH-Selections Syntax die einschlägigen Dokumentationen durch und übe damit sonst lernst du aus dem ganzen hier nichts.
https://www.w3schools.com/xml/xpath_syntax.asp
Danke für den Link! Über sowas bin ich immer Froh, da man ja Off keine Stelle hat wo man beginnen soll.

Grüße Uwe

p.s. Das ursprüngliche Problem dieses Threads wurde gelöst, alles andere ist jetzt Off-Topic.

Ja ist gelöst.
Ich probiere weiter.
149569
149569 28.09.2021 aktualisiert um 13:23:25 Uhr
Goto Top
Zitat von @SPSman:
Das ist nicht Korrekt. Oben schrieb ich Zeile 8 und Zeile 16 soll verändert werden. (OPN_SOLL und OPN)

Da grätsch ich doch mal dazwischen ... hast du oben bei der 16 wohl ne 1 vergessen. In Zeile 6 findet man da nix mit "OPN" :-P.
:

Zitat von @SPSman:
Zu verändernde Stellen(Zeile 1,8,6,46):

Vielleicht solltest du beim Tippen mal die Fäustlinge ausziehen 🙈 .
SPSman
SPSman 28.09.2021 um 15:05:39 Uhr
Goto Top
Zitat von @149569:

Zitat von @SPSman:
Das ist nicht Korrekt. Oben schrieb ich Zeile 8 und Zeile 16 soll verändert werden. (OPN_SOLL und OPN)

Da grätsch ich doch mal dazwischen ... hast du oben bei der 16 wohl ne 1 vergessen. In Zeile 6 findet man da nix mit "OPN" :-P.
:

Zitat von @SPSman:
Zu verändernde Stellen(Zeile 1,8,6,46):

Vielleicht solltest du beim Tippen mal die Fäustlinge ausziehen 🙈 .

Meinst du das hilft? :O
149569
149569 28.09.2021 aktualisiert um 15:14:28 Uhr
Goto Top
Zitat von @SPSman:
Meinst du das hilft? :O
Wer weiß das schon, wenn deine Tasten 10x10cm groß sind dann wahrscheinlich nicht, außer du hast kein Zielwasser getrunken face-big-smile
SPSman
Lösung SPSman 30.09.2021, aktualisiert am 01.10.2021 um 21:06:02 Uhr
Goto Top
Hi Mein Endgültiges Script falls jemand hier liest:
Set-Location -path C:\OPN
#Array Objektname
$CSVData= Import-Csv -Path '.\OPN.csv' -Delimiter ';'  
$OPN_in ='C:\OPN\OPNOUT.xml'  
$OPN_Out='C:\OPN\imp\OPNIMP.xml'  

## CSV sortierung umdrehen
$CSV_reseve=$CSVData.Clone()
for ($i=1; $i -lt $CSVData.Length; $i++) {
$CSV_reseve[$i]= $CSVData[$CSVData.Length-$i]

}
#Splatennamen auslesen
$CSVSpalten = $CSVData | Get-member -MemberType 'NoteProperty' | Select-Object -ExpandProperty 'Name'  

# xml Objekt erstellen
$xml = New-Object XML
# xml laden
$xml.Load($OPN_in)

# Abfrage des ersten 'SW.Blocks.CompileUnit' Knotens 
$Bsp_NW = $xml.SelectSingleNode("//SW.Blocks.CompileUnit")  


# abbrechen wenn kein Knoten gefunden wurde.
if (!$Bsp_NW){
    throw "Error, 'SW.Blocks.CompileUnit' Node not found!"  
    exit 1
}

$z=0
foreach($Zeile in $CSV_reseve)
{
# erstelle eine Kopie des Knotens im Speicher
$NEU_NW = $Bsp_NW.Clone()
#Texte Ersetzen 
foreach($spalte in $CSVSpalten)
{
$NEU_NW.innerxml = $NEU_NW.innerxml -replace ($Spalte -replace "'"),($Zeile.$Spalte -replace "'")  
}

# id anpassen
$NEU_NW.Id = (100*$z).ToString()

# hänge den kopierten Knoten im selben Parent wie vom Original wieder ins XML ein
$Bsp_NW.ParentNode.InsertAfter($NEU_NW,$Bsp_NW)
}

#Basisdaten ändern
$xml.Document.'SW.Blocks.FC'.AttributeList.Name ='OPN_IMPORT'  
$xml.Document.'SW.Blocks.FC'.AttributeList.Number = [String]($xml.Document.'SW.Blocks.FC'.AttributeList.Number+'00')  


# speichere das geänderte xml unter neuem Namen
$xml.Save($OPN_Out)
#>