使用现有的XML +循环在Powershell中生成完整的XML [英] Use existing XML + Loop to generate full XML in Powershell
问题描述
自从我处理Powershell以来已经有很长时间了,但是我需要一种方法,通过该方法可以从我创建的模板中生成大型XML文件.
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.
我正在处理的XML如下:
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>
我想开发一个循环,让我读取XML,将变量$ t和$ i更新为for循环中定义的连续整数.我想将循环的每个迭代添加到单个XML输出中.
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++}
我在正确的轨道上吗?
谢谢,伙计们.
推荐答案
考虑 XSLT ,专用XML转换语言,使用其自己的内置count()
:count(../preceding-sibling::*)
代替$ i,而count(descendant::ItemConfig)
代替$ t.具体来说,第一个计数迭代地计数<ItemConfig>
个先前的同级兄弟(父节点下当前节点位置的标记),而第二个计数对所有<ItemConfig>
个节点进行计数.
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.
但是,您的需求需要特殊的XSLT 1.0解决方案,包括:
However, your needs require special XSLT 1.0 solutions including:
- 替换字符串:由于$ i在较大的文本值内(与$ t不同),请使用模板字符串替换,如下所示此处 @MarkEliot.
- 复制元素:要重复创建n次元素(例如200次),请使用递归模板生成多个元素,如下所示此处通过@DimitreNovatchev.
- Replace string: since $i is within a large text value (unlike $t), use the template string replacement as shown here by @MarkEliot.
- Replicate elements: to recreate elements n times such as 200, use the recursive template to generate multiple elements as shown here by @DimitreNovatchev.
PowerShell can run XSLT 1.0 scripts by interfacing to Windows' .NET XslCompiledTransform class. No need of for
looping.
XSLT 脚本
<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 脚本
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;
这篇关于使用现有的XML +循环在Powershell中生成完整的XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!