0

我有一个 XML 文件,我想从属性 = ruleId 的元素复制文本节点值(例如:CIAV819)并将其粘贴到属性 = ruleExpression 的下一个节点元素。下面是我要修改的 XML 文件:

   <?xml version="1.0" encoding="UTF-8"?>
    <Main>
        <installObj uniqueObjects="2822">
            <object class="Installer">
                <visualChildren>
                    <object class="InstallSet">
                        <installchildrenMain>
                            <object class="InstallBundle1">
                                <property name="ruleExpression">
                                    <string><![CDATA[]]></string>  ---paste1
                                </property>
                                <property name="bundleName">
                                    <string><![CDATA[Australia]]></string>
                                </property>
                                <rules logicalOperation="AND">
                                    <object class="CompareVariable">
                                        <property name="ruleId">
                                           <string><![CDATA[CIAV819]]></string> --copy1
                                        </property>
                                        <property name="operandOne">
                                           <string><![CDATA[$FEATURE$]]></string>
                                        </property>
                                    </object>
                                </rules>
                                <installChildren>
                                    <object class="InstallComponent1">
                                        <property name="ruleExpression">
                                            <string><![CDATA[]]></string>  --paste2
                                        </property>    
                                        <property name="componentName">
                                            <string><![CDATA[AUST]]></string>
                                        </property>
                                        <rules logicalOperation="AND">
                                            <object class="CompareVariable">
                                                <property name="ruleId">
                                                    <string><![CDATA[CIAV962]]></string> --copy2.1
                                                </property>
                                                <property name="operandOne">
                                             <string><![CDATA[$FEATURE$]]></string>
                                       </property>
                                             </object>
                                             <object class="CompareVariable">
                             <property name="ruleId">
                                <string><![CDATA[CIAV503]]></string> --copy2.2
              </property>
                                             </object>
                                            </rules>
                                        <installChildren>
                                            <object class="InstallDirCont">
                                                <property name="ruleExpression">
                                                    <string><![CDATA[]]></string>  --paste3
                                                </property>
                                                <property name="operandOne">
                                             <string><![CDATA[$FEATURE$]]></string>
                                     </property>
                                                <rules logicalOperation="OR">
                                                    <object class="CompareVariable1">
                                                        <property name="ruleId">
                                                            <string><![CDATA[CIAV100]]></string> --COPY3.1 </property>
                                                        <property name="operandOne">
                                                    <string><![CDATA[$FEATURE$]]></string>  </property>

                                                    </object>
                                                    <object class="CompareVariable2">
                                                        <property name="ruleId">
                                                            <string><![CDATA[CIAV200]]></string><!-- COPY3.2 -->
                                                        </property>
                                                        <property name="operandOne">
                                                   <string><![CDATA[$FEATURE$]]></string>
                                            </property>

                                                    </object>
                                                </rules>
                                            </object>
                                        </installChildren>
                                    </object><!-- end of installComponent1 -->
                                    <object class="InstallComponent2" >
                                        <!--
                                        Same as above (Install Component1)
                                        -->
                                    </object><!-- end of installComponent2 -->
                                </installChildren>   
                            </object><!-- end of installBundle1 -->
                            <object class="InstallBundle2" >
                                <!--
                                Same structure as InstallBundle1
                                -->
                            </object><!-- end of installBundle2 -->
                        </installchildrenMain>
                    </object><!-- end of InstallSet -->
                </visualChildren><!-- end of visualChildren -->
            </object><!-- end of Installer -->
        </installObj>
        <restorationObjects count="0"/>
    </Main>

将“CIAV819”值从 copy1 位置复制到 paste1 位置,对于其他 copy2 和 copy3 位置也是如此。其中例如 paste1 位置应如下所示:

<property name="ruleExpression">
   <string><![CDATA[CIAV819]]></string>  ---paste1
</property>

paste2 位置应如下所示:

<property name="ruleExpression">
   <string><![CDATA[CIAV962 && CIAV503]]></string>  ---paste2
</property>

paste3 位置应如下所示:

<property name="ruleExpression">
   <string><![CDATA[CIAV100 || CIAV200]]></string>  ---paste3
</property>

只有当我在 InstallAnywhere 中打开这个 xml 文件时,我才能看到为规则表达式字段填充的值!我正在使用以下 XSLT 转换来获取我的输出:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:output cdata-section-elements="string" />
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<xsl:template match="//object[starts-with(@class, 'InstallBundle')]/property[@name='ruleExpression']">
    <xsl:copy>
        <xsl:copy-of select="../rules/object/property/string" />
    </xsl:copy>
</xsl:template>
<xsl:template match="//installChildren/object[starts-with(@class, 'InstallComponent')]/property[@name='ruleExpression']">
    <xsl:copy>
        <string>
           <xsl:for-each select="../rules[@logicalOperation='AND']/object">
                <xsl:value-of select="./rules/object/property/string" />
                <xsl:if test="position() &lt; count(../object)"><xsl:value-of select="' && '" /></xsl:if>
           </xsl:for-each>
        </string>
    </xsl:copy>
</xsl:template>
<xsl:template match="//installChildren/object/installChildren/object[@class='InstallDirCont']/property[@name='ruleExpression']">
    <xsl:copy>
        <string>
            <xsl:for-each select="../rules[@logicalOperation='OR']/object">
                <xsl:value-of select="./property/string" />
                <xsl:if test="position() &lt; count(../object)"><xsl:value-of select="' || '" /></xsl:if>
            </xsl:for-each>
        </string>
    </xsl:copy>
</xsl:template>
</xsl:transform>

我在我的 PHP 文件(如下所示)中运行这个 XSLT,它正在处理这个 xml/xslt 文件:

<?php
$xmldoc = new DOMDocument();
$xmldoc->load('ELS92.iap_xml');

$xsldoc = new DOMDocument();
$xsldoc->load('transform.xslt');

$xslt = new XSLTProcessor();
$xslt->importStylesheet($xsldoc);

$result = $xslt->transformToDoc($xmldoc);
$result->save($xmldoc);
?>

现在,当我在 CMD 中运行像“php test.php”这样的 php 文件时,我看到 xml 文件已更新,但例如:

  <property><string><![CDATA[CIAV100 || CIAV503]]></string></property>

代替

<property name="Expression">
              <string><![CDATA[CIAV100 || CIAV503]]></string>
           </property>

2013 年 11 月 11 日星期一:查询更新:

@Tim C:我做了一些快捷方式来避免 InstallAnywhere 软件使用冗长的名称。所以现在我对对象类“InstallBundle”的原始名称是“com.zerog.ia.installer.InstallBundle”,而对于“InstallComponent”它是“com.zerog.ia.installer.InstallComponent”。因此,在您的 xslt 中,我对模板进行了轻微修改,如下所示:

<xsl:template match="object[starts-with(@class, 'com.zerog.ia.installer.Install')]/property[@name='ruleExpression']">

我还添加了一个与“InstallDirCont”对象类匹配的新模板,该对象类最初命名为“com.zerog.ia.installer.actions.InstallDirCont”:

<xsl:template match="object[starts-with(@class, 'com.zerog.ia.installer.actions.InstallDirCont')]/property[@name='ruleExpression']">

这一切对我来说都很好。万分感谢!

但是现在,当我处理实时 InstallAnywhere 生成的文件时,我在 PHP 代码中发现了一些警告和错误。您介意我将项目文件发送给您吗?您可以查看更多内容并为 xml 文件找到一些异常处理函数吗?

查询更新时间:2013 年 11 月 15 日:

@Tim C:嗨,蒂姆,对不起,我需要进一步的帮助。通过新项目文件 (xml) 运行此 XSLT 后,我的原始 xml 文件将变为空白!可能是某些模板规则不匹配,无法进一步处理。但不确定。让我澄清一下,我的 xml 文件包含许多 InstallBundle 对象类,其中有多个 InstallCOMponent 和 InstallDirCONt 子对象类。现在我发现在其中一个 InstallBundle 对象类中

 `<property name="bundleName">
<string><![CDATA[*** ** Database **]]</string>
</property>` 

,它有一个安装组件

`<property name="componentName">
<string><![CDATA[Common]]></string>
</property>` 

它下面的结构不正确,而且没有 ruleId 值,因此我们不需要将其 ruleId 值复制到 ruleExpression 字段中。您能否更新 xslt 代码以绕过此条件并按照 InstallBundle 中包含的此“数据库”下的其他 installComponents 的过程进行操作?谢谢

4

1 回答 1

2

您可能应该首先编写一个与您希望更改的属性元素匹配的模板:

<xsl:template match="object[starts-with(@class, 'Install')]/property[@name='ruleExpression']">

但是此时您必须做的,以及您在示例中没有做的,不仅是复制现有元素,还包括它的属性

<xsl:copy>
    <xsl:apply-templates select="@*" />
    <!-- Code to get rules -->
</xsl:copy>

要获得实际的“规则”元素,在这种情况下,您似乎只想获得第一个以下同级。

 <xsl:apply-templates select="following-sibling::rules[1]" mode="copy" />

之所以mode="copy"在这里,是因为如果您有一个普通的模板匹配规则,它随后会破坏实际规则元素的副本。

在这个匹配“规则”的特殊模板中,您可以创建一个变量来确定正在使用什么操作“AND”或“OR”

<xsl:template match="rules" mode="copy">
    <xsl:variable name="operator">
       <xsl:choose>
          <xsl:when test="@logicalOperation='OR'"> || </xsl:when>
          <xsl:otherwise> &amp;&amp; </xsl:otherwise>
       </xsl:choose>
    </xsl:variable>

这意味着您可以避免任何代码重复,并且所有规则都可以使用相同的模板。

然后,这只是写出规则所需的所有属性的情况。

<xsl:for-each select="object/property[@name='ruleId']/string">
    <xsl:if test="position() > 1"><xsl:value-of select="$operator" /></xsl:if>
    <xsl:value-of select="." />
</xsl:for-each>

试试这个 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output cdata-section-elements="string" />

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

<xsl:template match="object[starts-with(@class, 'Install')]/property[@name='ruleExpression']">
    <xsl:copy>
        <xsl:apply-templates select="@*" />
        <string>
            <xsl:apply-templates select="following-sibling::rules[1]" mode="copy" />
         </string>
    </xsl:copy>
</xsl:template>

<xsl:template match="rules" mode="copy">
    <xsl:variable name="operator">
       <xsl:choose>
          <xsl:when test="@logicalOperation='OR'"> || </xsl:when>
          <xsl:otherwise> &amp;&amp; </xsl:otherwise>
       </xsl:choose>
    </xsl:variable>
    <xsl:for-each select="object/property[@name='ruleId']/string">
        <xsl:if test="position() > 1"><xsl:value-of select="$operator" /></xsl:if>
        <xsl:value-of select="." />
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

顺便说一句,您的 XSLT 格式不正确。任何实例都&需要转义为&amp;. 此外,在包含命名空间声明的xsl:transform元素之前还有xsl:output语句。

于 2013-10-31T13:06:18.100 回答