我有一个给定的源XML文档,其结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<sample>
<definition>
<variable>
<name>object01_ID_138368350261919620</name>
<value>NUL</value>
</variable>
<variable>
<name>param01_ID_138368350261919621</name>
<value>10</value>
</variable>
<variable>
<name>param02_ID_138368350261919622</name>
<value>100</value>
</variable>
</definition>
<override>
<assignment>
<name>object01_ID_138368350261919620</name>
<path>module01/object01</path>
</assignment>
<assignment>
<name>param01_ID_138368350261919621</name>
<path>module01/object01/param01</path>
</assignment>
<assignment>
<name>param02_ID_138368350261919622</name>
<path>module01/object01/param02</path>
</assignment>
</override>
</sample>
源XML的特征是:
<assignment>
元素中的每个<override>
元素仅对应<variable>
元素中的一个<definition>
元素。这种1:1关系由其<name>
元素的内容确定。
转换和目标XML的要求是:
根据{{1}}元素内容的模式,在<path>
元素的<assignment>
元素中,我想添加一个新的<override>
元素。需要注意的是,<assignment>
元素是主要信息。因此,首先必须创建一个包含<assignment>
和<assignment>
内容的新<path>
元素,并与相同的<name>
元素相同<variable>
元素1}}内容和特定的<name>
内容必须在<value>
元素的最后位置创建并插入。例如,要添加 param03 ,正确的结果应如下所示:
<definition>
用于转换的我的XSL 2.0样式表:
对于身份转换,我选择使用 [Dimitre Novatchev]推荐的细粒度控制身份规则。应用处理param03模板,我创建了一个新的<?xml version="1.0" encoding="UTF-8"?>
<sample>
<definition>
<variable>
<name>param00_ID_138368350261919620</name>
<value>NUL</value>
</variable>
<variable>
<name>param01_ID_138368350261919621</name>
<value>10</value>
</variable>
<variable>
<name>param02_ID_138368350261919622</name>
<value>100</value>
</variable>
<variable>
<name>Param03_ID_138368350261919623</name>
<value>1000</value>
</variable>
</definition>
<override>
<assignment>
<name>param00_ID_138368350261919620</name>
<path>module01/object01</path>
</assignment>
<assignment>
<name>param01_ID_138368350261919621</name>
<path>module01/object01/param01</path>
</assignment>
<assignment>
<name>param02_ID_138368350261919622</name>
<path>module01/object01/param02</path>
</assignment>
<assignment>
<name>Param03_ID_138368350261919623</name>
<xpath>module01/object01/param03</xpath>
</assignment>
</override>
</sample>
元素及其特定的<assignment>
和<path>
内容。在该模板中,我喜欢使用<name>
将节点上下文更改为for-each
元素,并在最后位置添加一个新的<definition>
元素以及相应的<variable>
内容,特定的<name>
内容。此样式表已经过Saxon HE 9.5测试。
<value>
产生错误的XML是:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="fo xs fn">
<!--
global declarations ==========================================================
-->
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- randomid here is just a fake for sake of simplification -->
<xsl:variable name="randomid" select="138368350261919623"/>
<!--
template - identity ==========================================================
-->
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()[1]"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<!--
template - variable assignment ===============================================
-->
<xsl:template name="variable_assignment">
<xsl:param name="value_node_name"/>
<xsl:param name="value_node_path"/>
<xsl:message select="'processing: variable assignment'"/>
<xsl:message select="concat('applying name: ', $value_node_name)"/>
<xsl:message select="concat('applying path: ', $value_node_path)"/>
<xsl:call-template name="identity"/>
<assignment>
<name>
<xsl:value-of select="$value_node_name"/>
</name>
<xpath>
<xsl:value-of select="$value_node_path"/>
</xpath>
</assignment>
</xsl:template>
<!--
template - processing param03 =============================================
-->
<xsl:template match="/sample/override[not(assignment
/path[matches(text(), '.*/object01/param03$')])]
/assignment[path[matches(text(), '.*/object01$')]]">
<!-- setting params -->
<xsl:param name="value_node_name_target">
<xsl:value-of select="concat('Param03_ID', '_', $randomid)"/>
</xsl:param>
<xsl:param name="value_node_path_target">
<xsl:value-of select="concat(./path, '/param03')"/>
</xsl:param>
<xsl:param name="value_node_value_target" select="'1000'"/>
<!-- processing variable assignment -->
<xsl:call-template name="variable_assignment">
<xsl:with-param name="value_node_name" select="$value_node_name_target"/>
<xsl:with-param name="value_node_path" select="$value_node_path_target"/>
</xsl:call-template>
<!-- processing variable definition -->
<xsl:for-each select="/sample/definition/*[position()=last()]">
<xsl:message select="'processing: variable definition'"/>
<xsl:message select="concat('Here we are: ', .)"/>
<xsl:message select="concat('applying name: ', $value_node_name_target)"/>
<xsl:message select="concat('applying value: ', $value_node_value_target)"/>
<xsl:call-template name="identity"/>
<variable>
<name>
<xsl:value-of select="$value_node_name_target"/>
</name>
<value>
<xsl:value-of select="$value_node_value_target"/>
</value>
</variable>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
我遇到的问题是:
<?xml version="1.0" encoding="UTF-8"?>
<sample>
<definition>
<variable>
<name>object01_ID_138368350261919620</name>
<value>NUL</value>
</variable>
<variable>
<name>param01_ID_138368350261919621</name>
<value>10</value>
</variable>
<variable>
<name>param02_ID_138368350261919622</name>
<value>100</value>
</variable>
</definition>
<override>
<assignment>
<name>object01_ID_138368350261919620</name>
<path>module01/object01</path>
</assignment>
<assignment>
<name>param01_ID_138368350261919621</name>
<path>module01/object01/param01</path>
</assignment>
<assignment>
<name>param02_ID_138368350261919622</name>
<path>module01/object01/param02</path>
</assignment>
<assignment>
<name>Param03_ID_138368350261919623</name>
<xpath>module01/object01/param03</xpath>
</assignment>
<variable>
<name>param02_ID_138368350261919622</name>
<value>100</value>
</variable>
<variable>
<name>Param03_ID_138368350261919623</name>
<value>1000</value>
</variable>
</override>
</sample>
元素会在最后一个位置添加到<variable>
元素中,而不是添加到<override>
元素中。<definition>
元素中的最后一个<variable>
元素将被复制到<definition>
元素中。那不是我想要的。 需要帮助!
如果有人可以建议我,我真的很感激,我必须调整我的XSLT以摆脱上面描述的问题和正确的行为。
非常感谢。
由您提出的XSLT 2.0,由我改编:
<override>
生成的XML(仍然错误):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fo xs fn">
<!--
global declarations ==========================================================
-->
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- baserandom here is just a fake for sake of simplification -->
<xsl:param name="baserandom" select="138368350261919623"/>
<!--MOVED PARAMS FROM ORIGINAL TEMPLATE HERE SO THEY CAN BE USED BY MULTIPLE TEMPLATES -->
<!--xsl:param name="value_node_path"-->
<!--I LEFT THE PREDICATE BECAUSE IT APPEARS THAT THERE COULD BE MORE THAN ONE override ELEMENT.-->
<!--xsl:value-of select="concat(/sample/override[not(assignment/path[matches(text(), '.*/object01/param03$')])]
/assignment[1]/path, '/param03')"/>
</xsl:param>
<xsl:param name="value_node_value" select="'1000'"/-->
<!--
template - identity ==========================================================
-->
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()[1]"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<!--
template - definition ========================================================
-->
<!--REPLACES THE xsl:for-each THAT PROCESSES THE VARIABLE DEFINITION-->
<xsl:template match="definition/*[last()]">
<xsl:param name="value_node_name"/>
<xsl:param name="value_node_value"/>
<xsl:call-template name="identity"/>
<xsl:if test="$value_node_name">
<xsl:message select="'processing: variable definition'"/>
<xsl:message select="concat('Here we are: ', .)"/>
<xsl:message select="concat('applying name: ', $value_node_name)"/>
<xsl:message select="concat('applying value: ', $value_node_value)"/>
<variable>
<name>
<xsl:value-of select="$value_node_name"/>
</name>
<value>
<xsl:value-of select="$value_node_value"/>
</value>
</variable>
</xsl:if>
</xsl:template>
<!--
template - processing param03 =============================================
-->
<xsl:template match="/sample/override[not(assignment/path[matches(text(), '.*/object01/param03$')])]
/assignment[path[matches(text(), '.*/object01$')]]">
<!-- name -->
<xsl:param name="value_node_name">
<xsl:value-of select="concat('param03_ID', '_', $baserandom)"/>
</xsl:param>
<!-- path -->
<xsl:param name="value_node_path">
<xsl:value-of select="concat(./path, '/param03')"/>
</xsl:param>
<!-- value -->
<xsl:param name="value_node_value" select="'1000'"/>
<!-- processing definition -->
<xsl:apply-templates select="/sample/definition/*[last()]">
<xsl:with-param name="value_node_name" select="$value_node_name"/>
<xsl:with-param name="value_node_value" select="$value_node_value"/>
</xsl:apply-templates>
<!-- processing assignment -->
<xsl:message select="'processing: variable assignment'"/>
<xsl:message select="concat('applying name: ', $value_node_name)"/>
<xsl:message select="concat('applying path: ', $value_node_path)"/>
<xsl:call-template name="identity"/>
<assignment>
<name>
<xsl:value-of select="$value_node_name"/>
</name>
<path>
<xsl:value-of select="$value_node_path"/>
</path>
</assignment>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:1)
您遇到的问题是xsl:for-each
未更改输出上下文。它只是改变迭代上下文。
当您在assignment
上进行迭代时,您仍在xsl:for-each select="/sample/definition/*[position()=last()]
(模板匹配)的上下文中输出。
您需要从variable
的上下文输出新的definition
。
我已经修改了你的XSLT以产生你想要的东西。它可能不是最终的解决方案,但应该让你更接近。我添加了评论(全部大写)以试图解释我改变了什么。如果有问题,请告诉我。
修改后的XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="fo xs fn">
<!--
global declarations ==========================================================
-->
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- randomid here is just a fake for sake of simplification -->
<xsl:param name="randomid" select="138368350261919623"/>
<!--MOVED PARAMS FROM ORIGINAL TEMPLATE HERE SO THEY CAN BE USED BY MULTIPLE TEMPLATES -->
<xsl:param name="value_node_name_target">
<xsl:value-of select="concat('Param03_ID', '_', $randomid)"/>
</xsl:param>
<xsl:param name="value_node_path_target">
<!--I LEFT THE PREDICATE BECAUSE IT APPEARS THAT THERE COULD BE MORE THAN ONE override ELEMENT.-->
<xsl:value-of select="concat(/sample/override[not(assignment/path[matches(text(), '.*/object01/param03$')])]
/assignment[1]/path, '/param03')"/>
</xsl:param>
<xsl:param name="value_node_value_target" select="'1000'"/>
<!--
template - identity ==========================================================
-->
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()[1]"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<!--
template - variable assignment ===============================================
-->
<!--MOVED CODE FROM THIS TEMPLATE INTO THE assignment TEMPLATE-->
<!--REPLACES THE xsl:for-each THAT PROCESSES THE VARIABLE DEFINITION-->
<xsl:template match="definition[../override[not(assignment/path[matches(text(), '.*/object01/param03$')])]
/assignment[path[matches(text(), '.*/object01$')]]]/*[last()]">
<xsl:message select="'processing: variable definition'"/>
<xsl:message select="concat('Here we are: ', .)"/>
<xsl:message select="concat('applying name: ', $value_node_name_target)"/>
<xsl:message select="concat('applying value: ', $value_node_value_target)"/>
<xsl:call-template name="identity"/>
<variable>
<name>
<xsl:value-of select="$value_node_name_target"/>
</name>
<value>
<xsl:value-of select="$value_node_value_target"/>
</value>
</variable>
</xsl:template>
<!--
template - processing param03 =============================================
-->
<xsl:template match="/sample/override[not(assignment/path[matches(text(), '.*/object01/param03$')])]
/assignment[path[matches(text(), '.*/object01$')]]">
<!-- setting params -->
<!--MOVED TEMPLATE PARAMS TO GLOBAL PARAMS-->
<!-- processing variable assignment -->
<!--REPLACED UNNECESSARY xsl:call-template WITH ACTUAL CODE-->
<xsl:message select="'processing: variable assignment'"/>
<xsl:message select="concat('applying name: ', $value_node_name_target)"/>
<xsl:message select="concat('applying path: ', $value_node_path_target)"/>
<xsl:call-template name="identity"/>
<assignment>
<name>
<xsl:value-of select="$value_node_name_target"/>
</name>
<!--CHANGED FROM xpath TO path (APPEARED TO BE A TYPO)-->
<path>
<xsl:value-of select="$value_node_path_target"/>
</path>
</assignment> <!-- processing variable definition -->
<!--THIS IS NOW DONE BY A SEPARATE MATCHING TEMPLATE-->
</xsl:template>
</xsl:stylesheet>
<强>输出强>
<sample>
<definition>
<variable>
<name>object01_ID_138368350261919620</name>
<value>NUL</value>
</variable>
<variable>
<name>param01_ID_138368350261919621</name>
<value>10</value>
</variable>
<variable>
<name>param02_ID_138368350261919622</name>
<value>100</value>
</variable>
<variable>
<name>Param03_ID_138368350261919623</name>
<value>1000</value>
</variable>
</definition>
<override>
<assignment>
<name>object01_ID_138368350261919620</name>
<path>module01/object01</path>
</assignment>
<assignment>
<name>param01_ID_138368350261919621</name>
<path>module01/object01/param01</path>
</assignment>
<assignment>
<name>param02_ID_138368350261919622</name>
<path>module01/object01/param02</path>
</assignment>
<assignment>
<name>Param03_ID_138368350261919623</name>
<path>module01/object01/param03</path>
</assignment>
</override>
</sample>