将节点包装在新的父节点中?

Wrap node in new parent node?

我正在使用 XSLT 样式表将 CSV 转换为 XML,但我还需要在 CSV 转换后使用一些模板转换 XML。下面是样式表的一部分,应该将任何 <UPC>031878025147</UPC> 节点包装为:

<UPCs> <UPC>031878025147</UPC> <UPCs>

这是应该用 <UPCs> 包裹 <UPC> 节点的样式表片段:

<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:fn="fn" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  version="2.0" exclude-result-prefixes="xs fn">
    <xsl:output method="xml" indent="yes" encoding="UTF-8" />

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

    <xsl:template match="//UPC[preceding-sibling::ExternalId]">
      <xsl:variable select="." name="curElem" />
      <xsl:for-each select=".">
        <UPCs>
          <xsl:copy-of select="$curElem" />
        </UPCs>
      </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

这是要解析的 XML 片段:

<Feed name="example" incremental="false" extractDate="2016-04-28T13:42:09-05:00" xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/14.5">
  <Brands>
    <Brand removed="false">
      <ExternalId>brands</ExternalId>
      <Name>Brands</Name>
      <!--BrandPageUrl>http://www.kolcraft.com/brands.html</BrandPageUrl-->
    </Brand>
    <!-- ... -->
  </Brands>
  <Categories>
    <Category removed="false">
      <ExternalId>baby-products</ExternalId>
      <Name>Baby Products</Name>
      <CategoryPageUrl>http://www.kolcraft.com/baby-products.html</CategoryPageUrl>
    </Category>
  </Categories>
  <Products>
    <Product>
      <ExternalId>ED003-QCX</ExternalId>
      <UPC>031878025147</UPC>
      <Name>Sealy Naturals-Cotton Crib Mattress Pad</Name>
      <Description>Give baby plush comfort from natural cotton fibers with the innovative Sealy Naturals-Cotton Crib Mattress Pad.</Description>
      <ProductPageUrl>http://www.kolcraft.com/sealy-naturals-cotton-crib-mattress-pad.html</ProductPageUrl>
      <ImageUrl>http://www.kolcraft.com/media/catalog/product/e/d/ed003-qcx-1_1_4.jpg</ImageUrl>
      <CategoryExternalId>crib-bedding</CategoryExternalId>
    </Product>
    <!-- ... -->
  </Products>
</Feed>

但是,这似乎没有捕获父 <UPCs> 节点之外的任何 <UPC> 节点。我在这里错过了什么?欢迎任何帮助。

这是因为您在 XML

中有一个默认的命名空间声明
<Feed ... xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/14.5">

这意味着 Feed 元素和所有后代元素都在该名称空间中。但是,您的 XSLT 没有考虑到这个名称空间,因此它正在寻找匹配一个不在名称空间中的元素 UPC,这不是一回事。

当您使用 XSLT 2.0 时,您实际上可以使用 xpath-default-namespace 为 xpath 表达式(如模板匹配)指定默认命名空间。您还需要为您的 XSLT 定义一个默认名称空间,以确保新的 UPCs 在同一名称空间中获得输出。

试试这个 XSLT

<xsl:stylesheet 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:fn="fn" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xpath-default-namespace="http://www.bazaarvoice.com/xs/PRR/ProductFeed/14.5"
  xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/14.5"
  version="2.0" exclude-result-prefixes="xs fn">
    <xsl:output method="xml" indent="yes" encoding="UTF-8" />

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

    <xsl:template match="UPC[preceding-sibling::ExternalId]">
        <UPCs>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
        </UPCs>
    </xsl:template>
</xsl:stylesheet>

请注意,我还简化了模板,因为我看不到 for-each 语句的新变量。

编辑:作为对评论的回应,请注意没有必要在模板匹配的开头使用双斜杠//