0

我想知道如何使用 xsl 模板将我的 xml 文档转换为另一个具有原始元素层次结构的 xml 文档。我还想为新生成的 XML 中的元素添加一些属性。

我的原始 XML 文件如下所示:

<shop> 
  <product>
    <cookie ID="001">
    <price>2</price>
    </cookie>
  </product>

  <product>
    <bread ID="002">
    <price>5</price>
    </bread>
  </product>

  <product>
    <milk ID="003">
    <price>2</price>
    </milk>
  </product>
</shop>

我想将其转换为以下 XML:

<newXML> 
  <newElement>
    <newElement ID="001">
    <newElement price="2"/>
    </newElement>
  </newElement>

  <newElement>
    <newElement ID="002">
    <newElement price="5"/>
    </newElement>
  </newElement>

  <newElement>
    <newElement ID="003">
    <newElement price="2"/>
    </newElement>
  </newElement>
</newXML>

什么是这样做的好方法?这可以使用带有模板的递归来完成,还是有更好的方法?我一直在尝试使用以下逻辑:

  1. 制作一个创建元素的模板
  2. 读取当前元素 ID(如果存在)并将其放入 newElement
  3. 如果当前元素有一个子元素,则将此模板应用于它(某种递归)

尽管进行了多次尝试,但我仍然无法完成这项工作。您的帮助将不胜感激!

4

2 回答 2

2

为此,您将构建 XSLT 身份转换,这是 XSLT 中非常常见的设计模式。首先,您只需一个模板,该模板可以复制元素并完全按原样输出]

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

然后你要做的是添加额外的模板来匹配你的元素,并添加代码来重命名它们,或者根据需要添加属性。例如,要重命名根元素,您将添加以下模板:

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

您也不必在此处使用特定的元素名称。如果您想将具有ID属性的元素重命名为相同的名称,您可以执行以下操作

<xsl:template match="product/*[@ID]">
   <newElement>
      <xsl:apply-templates select="@*|node()"/>
   </newElement>
</xsl:template>

对于您的价格元素,如果您想根据元素的文本内容创建一个属性,您可以像这样添加一个模板:

<xsl:template match="price">
   <newElement price="{.}" />
</xsl:template>

(注意,这使用属性值模板来创建属性。这通常比使用xsl:attribute更可取)

初学者试试这个 XML:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

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

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

   <xsl:template match="product/*[@ID]">
      <newElement>
         <xsl:apply-templates select="@*|node()"/>
      </newElement>
   </xsl:template>

   <xsl:template match="price">
      <newElement price="{.}" />
   </xsl:template>

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

这将输出以下内容:

<newXML>
   <newElement>
      <newElement ID="001">
         <newElement price="2"/>
      </newElement>
   </newElement>
   <newElement>
      <newElement ID="002">
         <newElement price="5"/>
      </newElement>
   </newElement>
   <newElement>
      <newElement ID="003">
         <newElement price="2"/>
      </newElement>
   </newElement>
</newXML>
于 2013-02-17T13:25:37.057 回答
0

听起来您只是想转换文档,那么为什么不尝试 XQuery 而不是 XSLT?就简单多了。。

您只需编写要创建的 xml,{..}如果您想从输入文件中插入一些内容,并for $variable in //xpath使用 xpath 表达式匹配的输入文件部分重复它。

因此,这将创建所需的 xml 文件:

<newXML>{
  for $prod in /shop/product/* return
    <newElement>
      <newElement>{
        $prod/@ID,
        for $value in $prod/* return 
          <newElement price="{$value}"/>
      }</newElement>
    </newElement>
}</newXML> 
于 2013-02-17T14:14:15.993 回答