我有一个XML结构,我想用XSLT转换它。但是,尽可能使其尽可能动态非常重要。我相信可以制作Feed的副本,然后只需选择一个特定的部分并对其进行转换。将新节点添加到原始XML时,在XSLT中不需要更改,以使此新节点包含在XSLT的输出中。
原始XML示例:
<?xml version="1.0" encoding="UTF-8"?>
<catalog week_id="629" generated_at="15.11.2017 23:53" version="2">
<item>
<lot>
<id>2982641</id>
<title_local><![CDATA[Title]]></title_local>
<sub_title_local>Subtitle</sub_title_local>
<promo>false</promo>
</lot>
<lot_specifics>
<case_material>
<name_local>Materiaal kast</name_local>
<name_en>Case material</name_en>
<slug>s-10-materiaal-kast</slug>
<option>
<value_local>Verguld</value_local>
<value_en>Gold-plated</value_en>
<slug_value>1750-verguld</slug_value>
</option>
<option>
<value_local>Zilver</value_local>
<value_en>Silver</value_en>
<slug_value>1751-silver</slug_value>
</option>
</case_material>
</lot_specifics>
<associations>
<category_id>1</category_id>
<auction_id>2</auction_id>
</associations>
</item>
</catalog>
期望的输出:
<?xml version="1.0" encoding="UTF-8"?>
<catalog week_id="629" generated_at="15.11.2017 23:53" version="2">
<item>
<lot>
<id>2982641</id>
<title_local><![CDATA[Title]]></title_local>
<sub_title_local>Subtitle</sub_title_local>
<promo>false</promo>
</lot>
<lot_specifics>
<case_material>
<name_local>Materiaal kast</name_local>
<name_en>Case material</name_en>
<slug>s-10-materiaal-kast</slug>
<value_local>Verguld,Silver</value_local>
<value_en>Gold-plated,Silver</value_en>
</case_material>
</lot_specifics>
<associations>
<category_id>1</category_id>
<auction_id>2</auction_id>
</associations>
</item>
</catalog>
我遇到了SO question that pretty much does what I'm aiming for,但我需要在此XSLT中定义完整的XML结构。由于我们可能会在以后的阶段添加其他XML节点,并且此XSLT将在各个地方使用,我希望尽可能降低维护。
我认为this SO question shows a low maintenance version但坦率地说,我无法理解第二个xsl:template
是如何运作的。
非常感谢所有帮助。如果提供了XSLT,如果您可以包含一些您正在做什么的评论,我将非常感激。
答案 0 :(得分:2)
由于您没有指定 XSLT 版本,我使用 2.0 , 这更强大,更适合这样的任务。
您的脚本应包含:
case_material
元素的模板。此模板应:
option
以外的所有元素。option
元素的特殊处理。此特殊处理应包括option
的所有子元素的分组
按元素名称。对于每个这样的小组,你应该:
我注意到你想&#34;排除&#34;某些元素(实际上只是
slug_value
),因此循环包含排除它们的条件。
所以整个脚本如下所示:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="case_material">
<xsl:copy>
<xsl:apply-templates select="*[name() != 'option']|@*"/>
<xsl:for-each-group select="option/*" group-by="name()">
<xsl:if test="current-grouping-key() != 'slug_value'">
<xsl:element name="{current-grouping-key()}">
<xsl:value-of select="current-group()" separator=","/>
</xsl:element>
</xsl:if>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
</xsl:template>
</xsl:stylesheet>
可以在 XSLT 1.0 中编写这样的脚本,但是你会这样做 必须编写更多代码,因为版本1.0不支持例如分组。
答案 1 :(得分:1)
我会尝试复制除option
元素之外的所有内容。迭代选项元素并对需要合并的项目进行分组。例如:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:param name="pGroupElems" as="xs:string *" select="'value_local', 'value_en'" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="case_material">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
<xsl:for-each-group select="option/*" group-by="local-name()[ . = $pGroupElems]">
<xsl:copy>
<xsl:sequence select="string-join(current-group(), ',')" />
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="option" />
</xsl:stylesheet>