有条件地将子节点移动到属性
Move child Nodes to attributes conditionally
我正在尝试转换此文档,但我对 xslt 还很陌生,并且在尝试将其正确处理时获得了很多乐趣。核心节点(为简单起见被截断)如下所示
<Product prod_id="6352">
<brandId>221</brandId>
<brand>Oscar Mayer</brand>
<images>
<smallimage>text</simage>
<medimage>text</medimage>
<largeimage>text</limage>
</images>
<nutrition>
<nutritionShow>Y</nutritionShow>
<servingSize>1 SLICE</servingSize>
<servingsPerContainer>12</servingsPerContainer>
<totalCalories>60</totalCalories>
<fatCalories>35</fatCalories>
<totalFat>4</totalFat>
<totalFatPercent>6</totalFatPercent>
<totalFatUnit>g</totalFatUnit>
<saturatedFat>1.5</saturatedFat>
<saturatedFatPercent>8</saturatedFatPercent>
<saturatedFatUnit>g</saturatedFatUnit>
<transFat>0</transFat>
<transFatUnit>g</transFatUnit>
<cholesterolUnit>mg</cholesterolUnit>
</nutrition>
<prodId>6352</prodId>
</Product>
最后我想将逻辑分组的子节点作为具有适当属性名称的单个节点。
最终结果应该是这样的
<Product prod_id="6352">
<brandId>221</brandId>
<brand>Oscar Mayer</brand>
<images>
<smallimage>text</smallimage>
<medimage>text</medimage>
<largeimage>text</largeimage>
</images>
<nutrition>
<nutritionShow>Y</nutritionShow>
<servingSize>1 SLICE</servingSize>
<servingsPerContainer>12</servingsPerContainer>
<totalCalories>60</totalCalories>
<fatCalories>35</fatCalories>
<totalFat amount="4" percent="6" unit="g" />
<saturatedFat amount="1.5" percent="8" unit="g"/>
<transFat amount="0" unit="g"</>
</nutrition>
<prodId>6352</prodId>
一些主要功能是
- 将相似的属性分组(注意 saturatedFat 和 transFat ... 略有不同)我有这些集合的离散列表。您可以使用列表或基于关系的更动态的东西,但要注意差异。
- 保留其他(不可分组)属性
- 忽略数量不足的群体attribute/only有单位属性(注意胆固醇)
提前感谢您帮助我理解这个相当复杂的转换。
一种可能的解决方案是遵循 XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="nutrition/*">
<xsl:variable name="cName" select="name()"/>
<xsl:choose>
<xsl:when test="following-sibling::node()[name()=concat($cName,'Unit')]">
<xsl:copy>
<xsl:attribute name="amount">
<xsl:value-of select="."/>
</xsl:attribute>
<xsl:if test="following-sibling::node()[name()=concat($cName,'Percent')]">
<xsl:attribute name="percent">
<xsl:value-of select="following-sibling::node()[name()=concat($cName,'Percent')]"/>
</xsl:attribute>
</xsl:if>
<xsl:attribute name="unit">
<xsl:value-of select="following-sibling::node()[name()=concat($cName,'Unit')]"/>
</xsl:attribute>
</xsl:copy>
</xsl:when>
<xsl:when test="contains(name() ,'Unit') or contains(name() ,'Percent')"/>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
当应用到您的输入时 XML 产生输出
<Product prod_id="6352">
<brandId>221</brandId>
<brand>Oscar Mayer</brand>
<images>
<smallimage>text</smallimage>
<medimage>text</medimage>
<largeimage>text</largeimage>
</images>
<nutrition>
<nutritionShow>Y</nutritionShow>
<servingSize>1 SLICE</servingSize>
<servingsPerContainer>12</servingsPerContainer>
<totalCalories>60</totalCalories>
<fatCalories>35</fatCalories>
<totalFat amount="4" percent="6" unit="g"></totalFat>
<saturatedFat amount="1.5" percent="8" unit="g"></saturatedFat>
<transFat amount="0" unit="g"></transFat>
</nutrition>
<prodId>6352</prodId>
</Product>
第一个模板是 Identity transform 并复制所有节点和属性而不做任何更改。
第二个模板匹配 nutrition
.
的所有子 elements/nodes
如果当前元素有一个本地名称与当前本地名称匹配并以 Unit
结尾的后续兄弟元素
<xsl:when test="following-sibling::node()[name()=concat($cName,'Unit')]">
当前节点必须是包含 amount
.
的节点
当前节点的值被写为 amount
属性的值
<xsl:attribute name="amount">
<xsl:value-of select="."/>
</xsl:attribute>
如果存在匹配 Percent
的下一个兄弟姐妹
<xsl:if test="following-sibling::node()[name()=concat($cName,'Percent')]">
Percent
属性相应地写成:
<xsl:attribute name="percent">
<xsl:value-of select="following-sibling::node()[name()=concat($cName,'Percent')]"/>
</xsl:attribute>
同样适用于 Unit
,无需预先检查是否存在匹配的 Unit
(如有必要,可以添加)。
空
<xsl:when test="contains(name() ,'Unit') or contains(name() ,'Percent')"/>
删除已写入属性的Unit
和Percent
节点以及cholesterolUnit
.
最后,仅复制所有其他不可分组的 nutrition
元素:
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:otherwise>
继续评论...
The example shows each of the 3 types of attributes. The others are as
one would expect ... you see saturated fat also could expct
unsaturated and monounsaturated and polyunsaturated There are 5-12 in
each category. Categories being 1. amount, unit and percent 2. amount
and unit 3. standalone
就我个人而言,我更喜欢把已知的东西拼出来,所以对于给定的例子:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- category #1: amount, unit and percent -->
<xsl:template match="totalFat">
<totalFat amount="{.}" percent="{../totalFatPercent}" unit="{../totalFatUnit}" />
</xsl:template>
<xsl:template match="saturatedFat">
<saturatedFat amount="{.}" percent="{../saturatedFatPercent}" unit="{../saturatedFatUnit}" />
</xsl:template>
<!-- category #2: amount and percent -->
<xsl:template match="transFat">
<transFat amount="{.}" unit="{../transFatUnit}" />
</xsl:template>
<!-- suppress all units and percents -->
<xsl:template match="totalFatPercent | totalFatUnit | saturatedFatPercent | saturatedFatUnit | transFatUnit | cholesterolUnit | cholesterolPercent"/>
</xsl:stylesheet>
请注意,类别 #3 由 身份转换 模板处理,无需例外。
另请注意,已知出现在每个产品中的项目不需要它们自己的模板;您可以将它们作为匹配 nutrition
的模板中的 文字结果元素 写出来,并将它们的名称添加到抑制空模板中。
我正在尝试转换此文档,但我对 xslt 还很陌生,并且在尝试将其正确处理时获得了很多乐趣。核心节点(为简单起见被截断)如下所示
<Product prod_id="6352">
<brandId>221</brandId>
<brand>Oscar Mayer</brand>
<images>
<smallimage>text</simage>
<medimage>text</medimage>
<largeimage>text</limage>
</images>
<nutrition>
<nutritionShow>Y</nutritionShow>
<servingSize>1 SLICE</servingSize>
<servingsPerContainer>12</servingsPerContainer>
<totalCalories>60</totalCalories>
<fatCalories>35</fatCalories>
<totalFat>4</totalFat>
<totalFatPercent>6</totalFatPercent>
<totalFatUnit>g</totalFatUnit>
<saturatedFat>1.5</saturatedFat>
<saturatedFatPercent>8</saturatedFatPercent>
<saturatedFatUnit>g</saturatedFatUnit>
<transFat>0</transFat>
<transFatUnit>g</transFatUnit>
<cholesterolUnit>mg</cholesterolUnit>
</nutrition>
<prodId>6352</prodId>
</Product>
最后我想将逻辑分组的子节点作为具有适当属性名称的单个节点。
最终结果应该是这样的
<Product prod_id="6352">
<brandId>221</brandId>
<brand>Oscar Mayer</brand>
<images>
<smallimage>text</smallimage>
<medimage>text</medimage>
<largeimage>text</largeimage>
</images>
<nutrition>
<nutritionShow>Y</nutritionShow>
<servingSize>1 SLICE</servingSize>
<servingsPerContainer>12</servingsPerContainer>
<totalCalories>60</totalCalories>
<fatCalories>35</fatCalories>
<totalFat amount="4" percent="6" unit="g" />
<saturatedFat amount="1.5" percent="8" unit="g"/>
<transFat amount="0" unit="g"</>
</nutrition>
<prodId>6352</prodId>
一些主要功能是
- 将相似的属性分组(注意 saturatedFat 和 transFat ... 略有不同)我有这些集合的离散列表。您可以使用列表或基于关系的更动态的东西,但要注意差异。
- 保留其他(不可分组)属性
- 忽略数量不足的群体attribute/only有单位属性(注意胆固醇)
提前感谢您帮助我理解这个相当复杂的转换。
一种可能的解决方案是遵循 XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="nutrition/*">
<xsl:variable name="cName" select="name()"/>
<xsl:choose>
<xsl:when test="following-sibling::node()[name()=concat($cName,'Unit')]">
<xsl:copy>
<xsl:attribute name="amount">
<xsl:value-of select="."/>
</xsl:attribute>
<xsl:if test="following-sibling::node()[name()=concat($cName,'Percent')]">
<xsl:attribute name="percent">
<xsl:value-of select="following-sibling::node()[name()=concat($cName,'Percent')]"/>
</xsl:attribute>
</xsl:if>
<xsl:attribute name="unit">
<xsl:value-of select="following-sibling::node()[name()=concat($cName,'Unit')]"/>
</xsl:attribute>
</xsl:copy>
</xsl:when>
<xsl:when test="contains(name() ,'Unit') or contains(name() ,'Percent')"/>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
当应用到您的输入时 XML 产生输出
<Product prod_id="6352">
<brandId>221</brandId>
<brand>Oscar Mayer</brand>
<images>
<smallimage>text</smallimage>
<medimage>text</medimage>
<largeimage>text</largeimage>
</images>
<nutrition>
<nutritionShow>Y</nutritionShow>
<servingSize>1 SLICE</servingSize>
<servingsPerContainer>12</servingsPerContainer>
<totalCalories>60</totalCalories>
<fatCalories>35</fatCalories>
<totalFat amount="4" percent="6" unit="g"></totalFat>
<saturatedFat amount="1.5" percent="8" unit="g"></saturatedFat>
<transFat amount="0" unit="g"></transFat>
</nutrition>
<prodId>6352</prodId>
</Product>
第一个模板是 Identity transform 并复制所有节点和属性而不做任何更改。
第二个模板匹配 nutrition
.
的所有子 elements/nodes
如果当前元素有一个本地名称与当前本地名称匹配并以 Unit
<xsl:when test="following-sibling::node()[name()=concat($cName,'Unit')]">
当前节点必须是包含 amount
.
的节点
当前节点的值被写为 amount
属性的值
<xsl:attribute name="amount">
<xsl:value-of select="."/>
</xsl:attribute>
如果存在匹配 Percent
的下一个兄弟姐妹
<xsl:if test="following-sibling::node()[name()=concat($cName,'Percent')]">
Percent
属性相应地写成:
<xsl:attribute name="percent">
<xsl:value-of select="following-sibling::node()[name()=concat($cName,'Percent')]"/>
</xsl:attribute>
同样适用于 Unit
,无需预先检查是否存在匹配的 Unit
(如有必要,可以添加)。
空
<xsl:when test="contains(name() ,'Unit') or contains(name() ,'Percent')"/>
删除已写入属性的Unit
和Percent
节点以及cholesterolUnit
.
最后,仅复制所有其他不可分组的 nutrition
元素:
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:otherwise>
继续评论...
The example shows each of the 3 types of attributes. The others are as one would expect ... you see saturated fat also could expct unsaturated and monounsaturated and polyunsaturated There are 5-12 in each category. Categories being 1. amount, unit and percent 2. amount and unit 3. standalone
就我个人而言,我更喜欢把已知的东西拼出来,所以对于给定的例子:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- category #1: amount, unit and percent -->
<xsl:template match="totalFat">
<totalFat amount="{.}" percent="{../totalFatPercent}" unit="{../totalFatUnit}" />
</xsl:template>
<xsl:template match="saturatedFat">
<saturatedFat amount="{.}" percent="{../saturatedFatPercent}" unit="{../saturatedFatUnit}" />
</xsl:template>
<!-- category #2: amount and percent -->
<xsl:template match="transFat">
<transFat amount="{.}" unit="{../transFatUnit}" />
</xsl:template>
<!-- suppress all units and percents -->
<xsl:template match="totalFatPercent | totalFatUnit | saturatedFatPercent | saturatedFatUnit | transFatUnit | cholesterolUnit | cholesterolPercent"/>
</xsl:stylesheet>
请注意,类别 #3 由 身份转换 模板处理,无需例外。
另请注意,已知出现在每个产品中的项目不需要它们自己的模板;您可以将它们作为匹配 nutrition
的模板中的 文字结果元素 写出来,并将它们的名称添加到抑制空模板中。