我需要将XML从源格式转换为目标名称值对以进行通用处理。有关如何实现这一目标的任何提示吗?我试图使用MapForce,如果它更容易。
这
<products>
<product>
<type>Monitor</type>
<size>22</size>
<brand>EIZO</brand>
</product>
<product>
......
</product>
</products>
到
<products>
<product num="1">
<attribute name="type">Monitor</attribute>
<attribute name="size">22</attribute>
<attribute name="brand">EIZO</attribute>
</product>
<product num="2">
....
</product>
</products>
我认为我需要在元素中使用xsl:for-each来生成元素?
&#34; num&#34;属性,它基本上只是一个计数器。它可能是位置()?
非常感谢!!
答案 0 :(得分:2)
对于这样的问题,您通常从构建XSLT标识模板开始
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
它自己按原样复制所有节点,这意味着您只需要为要转换的节点编写匹配的模板。
首先,您希望将 num 属性添加到产品,因此请使用与产品匹配的模板,您只需将其输出使用该属性并继续处理其子项。
<xsl:template match="product">
<product num="{position()}">
<xsl:apply-templates select="@*|node()"/>
</product>
</xsl:template>
请注意在创建 num 属性时使用属性值模板。花括号表示要计算的表达式,而不是字面输出。
然后,您希望模板与产品元素的子元素匹配,并将这些元素转换为属性节点。这是通过一个模式来匹配任何这样的孩子,如此
<xsl:template match="product/*">
<attribute name="{local-name()}">
<xsl:apply-templates />
</attribute>
</xsl:template>
请注意,如果您在子元素中只有文本节点,<xsl:apply-templates />
可以替换为<xsl:value-of select="." />
。
试试这个XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="product">
<product num="{position()}">
<xsl:apply-templates select="@*|node()"/>
</product>
</xsl:template>
<xsl:template match="product/*">
<attribute name="{local-name()}">
<xsl:apply-templates />
</attribute>
</xsl:template>
</xsl:stylesheet>
当应用于XML时,输出以下内容
<products>
<product num="1">
<attribute name="type">Monitor</attribute>
<attribute name="size">22</attribute>
<attribute name="brand">EIZO</attribute>
</product>
<product num="2">
......
</product>
</products>
当然,如果确实想要将子元素转换为适当的属性,而不是名为“attribute”的元素,则可以使用 xsl:attribute 命令。用这个
替换最后一个模板<xsl:template match="product/*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
当使用此模板时,输出以下内容(如果您的样本具有子元素,那么它将包含产品2)。
<products>
<product num="1" type="Monitor" size="22" brand="EIZO"></product>
<product num="2">
......
</product>
</products>
答案 1 :(得分:0)
我想我有你想要的东西。不适用于每个条款。只是递归模板的神奇之处:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="products">
<products>
<xsl:call-template name="transformProducts">
<xsl:with-param name="nodes" select="product"/>
</xsl:call-template>
</products>
</xsl:template>
<xsl:template name="transformProducts">
<xsl:param name="nodes"/>
<xsl:param name="counter" select="0"/>
<xsl:choose>
<xsl:when test="not($nodes)"></xsl:when>
<xsl:otherwise>
<product>
<xsl:attribute name="num">
<xsl:value-of select="$counter + 1"/>
</xsl:attribute>
<xsl:attribute name="type">
<xsl:value-of select="$nodes[1]/type"/>
</xsl:attribute>
<xsl:attribute name="size">
<xsl:value-of select="$nodes[1]/size"/>
</xsl:attribute>
<xsl:attribute name="brand">
<xsl:value-of select="$nodes[1]/brand"/>
</xsl:attribute>
</product>
<xsl:call-template name="transformProducts">
<xsl:with-param name="nodes" select="$nodes[position() > 1]"/>
<xsl:with-param name="counter" select="$counter + 1"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
根据我的测试,这是起始XML:
<products>
<product>
<type>Monitor</type>
<size>22</size>
<brand>EIZO</brand>
</product>
<product>
<type>MonitorTwo</type>
<size>32</size>
<brand>SONY</brand>
</product>
<product>
<type>what</type>
<size>12</size>
<brand>VGA</brand>
</product>
</products>
这是输出。我假设通过命名你的元素“属性”,你实际上意味着他们被转换为产品元素的属性节点?
<products>
<product num="1" type="Monitor" size="22" brand="EIZO"/>
<product num="2" type="MonitorTwo" size="32" brand="SONY"/>
<product num="3" type="what" size="12" brand="VGA"/>
</products>
答案 2 :(得分:0)
当然,天堂禁止这应该简短,因为......为什么呢?
版本A(名为“属性”的元素):
<xsl:template match="/">
<products>
<xsl:for-each select="products/product">
<product num="{position()}">
<xsl:for-each select="*">
<attribute name="{name()}">
<xsl:value-of select="."/>
</attribute>
</xsl:for-each>
</product>
</xsl:for-each>
</products>
</xsl:template>
版本B(真实属性):
<xsl:template match="/">
<products>
<xsl:for-each select="products/product">
<product num="{position()}">
<xsl:for-each select="*">
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
</product>
</xsl:for-each>
</products>
</xsl:template>
答案 3 :(得分:0)
全心全意,
Tim和Phillips的方法都非常不同,但两者都很完美。我是否正确的思考
Tim的方法基于Source XML,然后使用模板调整指定的内容。如果我有100个元素并且只想调整一些,那么这是一个很好的元素。
Phillip方法正在从头开始构建一个新的XML,但是XPath-ing /提取出我想要的东西。说如果我有100个元素,我只想提取和转换一些输出,那么这是一个很好的。
非常感谢!
答案 4 :(得分:-1)
尚未对此进行测试,但您可以执行以下操作:
<products>
<xsl:for-each select="//product">
<product num="{position()}">
<xsl:for-each select="current()/*">
<attribute name="{name()}">
<xsl:value-of select="self::node()/text()"/>
</attribute>
</xsl>
</product>
</xsl>
</products>