2017-02-16 2 views
0

J'ai vraiment du mal à manipuler du code XML dans PowerShell que je dois renvoyer à un service Web en tant que corps. Quelqu'un pourrait-il m'aider à faire en sorte que le XML soit présenté comme il le faut?Insérer un nouveau nœud XML après un autre nœud

<?xml version="1.0" encoding="UTF-8"?> 
<EdgeGateway> 
<Configuration> 
    <GatewayInterfaces> 
     <GatewayInterface> 
      <InterfaceType>uplink</InterfaceType> 
      <SubnetParticipation> 
       <Gateway>1.2.3.4</Gateway> 
       <Netmask>255.255.255.240</Netmask> 
       <IpAddress>1.2.3.5</IpAddress> 
# Missing the IpRange XML section - defined below 
       <UseForDefaultRoute>true</UseForDefaultRoute> 
      </SubnetParticipation> 
      <UseForDefaultRoute>true</UseForDefaultRoute> 
     </GatewayInterface> 
    </GatewayInterfaces> 
</Configuration> 
</EdgeGateway> 

doit devenir:

<?xml version="1.0" encoding="UTF-8"?> 
<EdgeGateway> 
<Configuration> 
    <GatewayInterfaces> 
     <GatewayInterface> 
      <InterfaceType>uplink</InterfaceType> 
      <SubnetParticipation> 
       <Gateway>1.2.3.4</Gateway> 
       <Netmask>255.255.255.240</Netmask> 
       <IpAddress>1.2.3.5</IpAddress> 
# New Content added here 
       <IpRanges> 
        <IpRange> 
         <StartAddress>1.2.3.5</StartAddress> 
         <EndAddress>1.2.3.5</EndAddress> 
        <IpRange> 
       </IpRanges> 
# End of new content 
       <UseForDefaultRoute>true</UseForDefaultRoute> 
      </SubnetParticipation> 
      <UseForDefaultRoute>true</UseForDefaultRoute> 
     </GatewayInterface> 
    </GatewayInterfaces> 
</Configuration> 
</EdgeGateway> 

Jusqu'à présent, j'ai pu créer de nouveaux noeuds XML/Eléments du nouveau contenu, mais je ne peux pas l'obtenir à insérer au bon endroit. Je peux obtenir la méthode AppendChild() pour travailler, mais il met le contenu après la section <UseForDefaultRoute> - pas avant.

J'ai essayé de faire InsertBefore() et InsertAfter(), mais cela ne veut tout simplement pas fonctionner. Enfin, quand je fais l'approche AppendChild(), je reçois aussi un peu de texte supplémentaire auquel je ne m'attendais pas, quelque chose à propos de xmlns?

<IpRanges xmlns=""><IpRange><StartAddress>1.2.3.5</StartAddress><EndAddress>1.2.3.5</EndAddress></IpRange></IpRanges> 

C'est ce que je réussi à mettre ensemble, gardez à l'esprit qu'il est cassé :(

# load XML file 
[xml]$doc = $response 

# create node <StartAddress> 
$startNode = $doc.CreateNode('element', 'StartAddress', '') 
$start = $doc.CreateTextNode('1.2.3.5') 
$startNode.AppendChild($start) | Out-Null 

# create node <EndAddress> 
$endNode = $doc.CreateNode('element', 'EndAddress', '') 
$end = $doc.CreateTextNode('1.2.3.5') 
$endNode.AppendChild($end) | Out-Null 

# create node <IpRange> and append child nodes <StartAddress> and  <EndAddress> 
$ipRange = $doc.CreateNode('element', 'IpRange', '') 
$ipRange.AppendChild($startNode) | Out-Null 
$ipRange.AppendChild($endNode) | Out-Null 

# create node <IpRanges> and append child nodes <IpRange> 
$ipRanges = $doc.CreateNode('element', 'IpRanges', '') 
$ipRanges.AppendChild($ipRange) | Out-Null 

# append node <IpRanges> to node <SubnetParticipation> 
$subnetParticpation = $doc.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[1].SubnetParticipation.AppendChild($ipRanges) 

... suivant les conseils de Ansgar, ceci est ma tentative d'utiliser un espace de noms. (Cassé)

[xml]$fragment = "<dummy xmlns:xsi='http://www.vmware.com/vcloud/v1.5'><IpRanges>$($ipRanges.InnerXml)</IpRanges></dummy>" 

# $fragment.InnerXml ..returns.. 
# <dummy xmlns:xsi="http://www.vmware.com/vcloud/v1.5"><IpRanges><IpRange><StartAddress>185.39.247.98</StartAddress><EndAddress>185.39.247.98</EndAddress></IpRange></IpRanges></dummy> 

# $body is the full XML Document I want to paste into 
[xml]$xml = $body 

$nsm = New-Object Xml.XmlNamespaceManager $xml.NameTable 
$nsm.AddNamespace('xsi', $xml.NamespaceURI) 
$node = $xml.ImportNode($fragment.DocumentElement.IpRanges, $true) 

$subnetPart = $xml.SelectSingleNode("//IpAddress[text()='185.39.247.98']", $nsm) 
$subnetPart 

# returns nothing 
+0

"ne veut pas travailler" est une description du problème insuffisant. Qu'avez-vous essayé exactement? Et quels ont été les résultats de cette tentative? –

+0

Bien sûr, je vais l'ajouter ci-dessus dans les modifications, je ne voulais pas poser une question massive, alors désolé j'ai fini par laisser cette partie. –

Répondre

0

Tenez compte XSLT, le but spécial, la langue du W3C-conçu pour transformer conforme fichiers XML à d'autres XML, HTML, même les formats de texte. PowerShell peut appeler le haut-XslCompiledTransform Classe transmettant les arguments du fichier source, du script xslt et du fichier de sortie.

XSLT(utilise l'identité Transform pour copier tout comme et met à jour le nœud SubnetParticipation)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output version="1.0" encoding="UTF-8" indent="yes" method="xml"/> 
<xsl:strip-space elements="*"/> 

    <!-- Identity Transform --> 
    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="SubnetParticipation"> 
    <xsl:copy> 
     <xsl:apply-templates /> 
     <IpRanges> 
     <IpRange> 
      <StartAddress>1.2.3.5</StartAddress> 
      <EndAddress>1.2.3.5</EndAddress> 
     </IpRange> 
     </IpRanges> 
    </xsl:copy> 
    </xsl:template> 

</xsl:transform> 

PowerShell

param ($xml, $xsl, $output) 

if (-not $xml -or -not $xsl -or -not $output) { 
    Write-Host "& .\xslt.ps1 [-xml] xml-input [-xsl] xsl-input [-output] transform-output" 
    exit; 
} 

trap [Exception]{ 
    Write-Host $_.Exception; 
} 

$xslt = New-Object System.Xml.Xsl.XslCompiledTransform; 

$xslt.Load($xsl); 
$xslt.Transform($xml, $output); 

Write-Host "generated" $output; 

ligne de commande appel (ou script batch appel)

Powershell.exe -File "C:\Path\To\PowerShell\Script.ps1" 
"C:\Path\To\Source.xml" "C:\Path\To\Transform.xsl" "C:\Path\To\Output.xml" 

Sortie

<?xml version="1.0" encoding="utf-8"?> 
<EdgeGateway> 
    <Configuration> 
    <GatewayInterfaces> 
     <GatewayInterface> 
     <InterfaceType>uplink</InterfaceType> 
     <SubnetParticipation> 
      <Gateway>1.2.3.4</Gateway> 
      <Netmask>255.255.255.240</Netmask> 
      <IpAddress>1.2.3.5</IpAddress> 
      <UseForDefaultRoute>true</UseForDefaultRoute> 
      <IpRanges> 
      <IpRange> 
       <StartAddress>1.2.3.5</StartAddress> 
       <EndAddress>1.2.3.5</EndAddress> 
      </IpRange> 
      </IpRanges> 
     </SubnetParticipation> 
     <UseForDefaultRoute>true</UseForDefaultRoute> 
     </GatewayInterface> 
    </GatewayInterfaces> 
    </Configuration> 
</EdgeGateway> 
+0

Merci pour la suggestion, cela * sonne * intéressant, mais comme je veux tout faire à partir d'un script, j'ai essayé de réécrire ce que vous avez posté. Je devine que cela ne fonctionne pas parce que la méthode .load s'attend à lire un élément d'un système de fichiers? - Je ne sais pas comment faire pour charger le XSL. –

+0

Votre code XML ne se charge-t-il pas en externe?Notez que XSL * est * un fichier XML bien formé et peut être manipulé comme n'importe quel fichier XML, y compris en lecture depuis une chaîne incorporée. Ah ... encore une fois l'impressionnant XSLT récursif revient au coffre-fort inutilisé, méconnu, largement ignoré. Nous avons essayé cependant sur PHP, Python, Java, maintenant les cartes PowerShell! – Parfait

0

Vous pouvez insérer le nouveau nœud après un autre noeud comme celui-ci:

$node = $doc.SelectSingleNode("//IpAddress[text()='1.2.3.5']") 
$node.ParentNode.InsertAfter($ipRanges, $node) 
+0

Chaque fois que j'ai utilisé la notation //, il n'a pas réussi à trouver le nœud IpAddress, abandonnant le // de la sélection travaillée dans ISE. Pour rendre la chose plus confuse pour moi, l'approche qui a fonctionné dans ISE (using SelectSingleNode) ne fonctionne pas (avec ou sans //) dans l'environnement réel, je pense que cela pourrait être un problème de type d'objet. $ test = $ body.SelectSingleNode ("// IpAddress [text() = '1.2.3.5']") $ test ... ne retourne rien –

+0

... aussi, quand je fais un Get-Member sur le nœud parent, je reçois le code suivant: TypeName: System.Xml.XmlElement # http: //www.vmware.com/vcloud/v1.5#SubnetParticipation –

+0

@DavidHocking Le code que j'ai affiché fonctionne très bien avec l'exemple XML que vous avez posté . Si cela ne fonctionne pas avec vos données en direct, vos données en direct sont différentes de vos données d'échantillon. Veuillez mettre à jour votre exemple XML pour qu'il ressemble davantage à vos données en direct. En sortant d'une branche, je suppose que vous avez des espaces de noms dans le XML original. –