我有一个XML文件,我想从带有attribute = ruleId的元素复制文本节点值(例如:CIAV819),并将其粘贴到具有attribute = 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文件时,我才能看到为Rule Expression字段填充的值! 我使用下面的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() < 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() < 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文件“php test.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&amp; InstallDirCOnt子对象类。现在我发现它在InstallBundle对象类中的一个
`<property name="bundleName">
<string><![CDATA[*** ** Database **]]</string>
</property>`
,它有一个带
的Installcomponent`<property name="componentName">
<string><![CDATA[Common]]></string>
</property>`
下面有一个不正确的结构,而且没有ruleId值,因此我们不需要将其ruleId值复制到ruleExpression字段中。你能否更新xslt代码以绕过这个条件,并按照InstallBundle中包含的这个'Database'下的其他installComponents的流程进行操作?感谢
答案 0 :(得分: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> && </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> && </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格式不正确。 &
的任何实例都需要转义为&
。您还需要在 xsl:transform 元素之前发生 xsl:output 语句,该元素包含名称空间声明。