1

我需要将 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 来生成元素?

“num”属性怎么样,它基本上只是一个计数器。它可以是位置()吗?

非常感谢!!

4

5 回答 5

2

对于此类问题,您通常从构建 XSLT 标识模板开始

<xsl:template match="@*|node()">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>

就其本身而言,它会按原样复制所有节点,这意味着您只需为要转换的节点编写匹配的模板。

首先,您希望将num属性添加到product,因此有一个模板匹配product,您只需将其与属性一起输出并继续处理其子项。

<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>
于 2014-02-15T10:00:17.093 回答
0

谢谢大家,

Tim 和 Phillips 的方法都非常不同,但都非常有效。我的想法是否正确

  • Tim 的方法基于 Source XML,然后使用模板来调整任何指定的内容。假设我有 100 个元素并且只想调整几个元素,那么这是一个很好的元素。

  • Phillip 方法是从头开始构建一个新的 XML,但是 XPath-ing/提取出我想要的东西。假设如果我有 100 个元素并且我只想提取和转换一些作为输出,那么这是一个很好的。

非常感谢!

于 2014-02-15T22:07:11.633 回答
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>
于 2014-02-15T10:50:00.617 回答
0

我想我有你要找的东西。没有 for-each 子句。只是递归模板的魔力:

<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>
于 2014-02-15T07:15:54.800 回答
-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>
于 2014-02-14T23:41:02.077 回答