使用现有的XML +循环在Powershell中生成完整的XML [英] Use existing XML + Loop to generate full XML in Powershell

查看:78
本文介绍了使用现有的XML +循环在Powershell中生成完整的XML的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

自从我处理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:

  1. 替换字符串:由于$ i在较大的文本值内(与$ t不同),请使用模板字符串替换,如下所示此处 @MarkEliot.
  2. 复制元素:要重复创建n次元素(例如200次),请使用递归模板生成多个元素,如下所示此处通过@DimitreNovatchev.
  1. Replace string: since $i is within a large text value (unlike $t), use the template string replacement as shown here by @MarkEliot.
  2. Replicate elements: to recreate elements n times such as 200, use the recursive template to generate multiple elements as shown here by @DimitreNovatchev.

PowerShell可以通过与Windows的

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆