It's been a long while since I've dealt with Powershell, but I'm in need of a method by which to generate a large XML file from a template that I've created.
The XML I'm dealing with looks like this:
<Project>
<Groups>
<GroupConfig typeKey="standard" name="$t" path="TTC/TTC1">
<Property name="CONFIGURED_ITEMS" isComplex="true">
<ItemConfig name="Bot_Setpoint" typeId="0">
<Property name="TARGET_DATA_TYPE">4</Property>
<Property name="SCALEDHIGH">0.1</Property>
<Property name="ALERTMESSAGEMODE">0</Property>
<Property name="RAWLOW">0.0</Property>
<Property name="ALERTMODE">0</Property>
<Property name="EXPRESSIONTYPE">0</Property>
<Property name="SCALEDLOW">0.0</Property>
<Property name="VALUE"></Property>
<Property name="OPCITEMPATH">ns=1;s=[TTC_1]N55:$i</Property>
<Property name="ALERTNOTES"></Property>
<Property name="ALERTTIMESTAMPSOURCE">0</Property>
<Property name="ALERTDEADBAND">0.0</Property>
<Property name="CLAMPMODE">0</Property>
<Property name="OPCSERVER">Ignition OPC-UA Server</Property>
<Property name="ALERTACKMODE">1</Property>
<Property name="SCALEMODE">1</Property>
<Property name="ALERTMESSAGE"></Property>
<Property name="EXPRESSION"></Property>
<Property name="ALERTMESSAGESUBJECT"></Property>
<Property name="RAWHIGH">1.0</Property>
<Property name="DEADBAND">0.0</Property>
<Property name="TARGET_NAME">Bot_Setpoint</Property>
</ItemConfig>
I'd like to develop a loop that lets me read the XML, update the variables $t and $i to successive integers defined in the for loop. I'd like to add each iteration of the loop to a single XML output.
In my mind, the (pseudo)code looks something like the following:
[xml]$xml = (Get-Content -Path xmlpath.xml)
$t = 1
for($i = 0; $i -lt 201; $i++){
read xml contents
replace $i in XML with current $i value
replace $t in XML with current $t value
write new XML segment to newfile.xml
$t = $t++}
Am I on the right track?
Thanks in advance, folks.
Consider XSLT , the special-purpose XML transformation language, using its own built-in count()
: count(../preceding-sibling::*)
for $i replacement and count(descendant::ItemConfig)
for $t replacement. Specifically, the first count iteratively counts the <ItemConfig>
previous siblings (a marker for current node position under parent) while the second counts all <ItemConfig>
nodes.
However, your needs require special XSLT 1.0 solutions including:
PowerShell can run XSLT 1.0 scripts by interfacing to Windows' .NET XslCompiledTransform class . No need of for
looping.
XSLT Script
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pTimes" select="200"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GroupConfig">
<xsl:copy>
<xsl:copy-of select="@typeKey"/>
<xsl:attribute name="name"><xsl:value-of select="count(descendant::ItemConfig)"/></xsl:attribute>
<xsl:copy-of select="@path"/>
<xsl:apply-templates select="Property"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ItemConfig/Property[contains(., '$i')]">
<xsl:copy>
<xsl:variable name="elem_count">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="." />
<xsl:with-param name="replace" select="'$i'" />
<xsl:with-param name="by" select="count(../preceding-sibling::*)+1" />
</xsl:call-template>
</xsl:variable>
<xsl:copy-of select="@*"/>
<xsl:value-of select="$elem_count"/>
</xsl:copy>
</xsl:template>
<!-- String Replacement -->
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="$text = '' or $replace = ''or not($replace)" >
<xsl:value-of select="$text" />
</xsl:when>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Recurisive Iteration -->
<xsl:template match="/*">
<xsl:copy>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes"/>
<xsl:with-param name="pPosition" select="1"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="applyNTimes">
<xsl:param name="pTimes" select="0"/>
<xsl:param name="pPosition" select="1"/>
<xsl:if test="$pTimes > 0">
<xsl:apply-templates select="*">
<xsl:with-param name="pPosition" select="$pPosition"/>
</xsl:apply-templates>
<xsl:call-template name="applyNTimes">
<xsl:with-param name="pTimes" select="$pTimes -1"/>
<xsl:with-param name="pPosition" select="$pPosition+1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
PowerShell Script
trap [Exception]{
Write-Host $_.Exception;
}
$xslt = New-Object System.Xml.Xsl.XslCompiledTransform;
$xslt.Load('C:\Path\To\XSLT\Script.xsl');
$xslt.Transform('C:\Path\To\Input.xml',
'C:\Path\To\Output.xml');
Write-Host "generated" $output;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.