I'm not entirely sure where my error is currently with my stylesheet here:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet exclude-result-prefixes="exsl xs"
extension-element-prefixes="exsl" version="2.0"
xmlns:exsl="http://exslt.org/common"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--xsl:import-schema schema-location="ProductFeed5.6.xsd" / -->
<xsl:output method="xml" indent="yes" encoding="UTF-8"
byte-order-mark="no" omit-xml-declaration="no"
xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" />
<xsl:strip-space elements="*" />
<!-- Parameter to determine when using 'contoursbaby' or 'kolcraft' feed
values -->
<xsl:param name="feedName" as="xs:string" />
<!-- copy all nodes that do not match a given template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:choose>
<xsl:when test="starts-with(name(), 'dataroot_')">
<xsl:element name="Feed" namespace="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6">
<xsl:attribute name="name" select="$feedName" />
<xsl:attribute name="incremental" select="'false'" />
<xsl:attribute name="extractDate"><xsl:value-of select='current-dateTime()' /></xsl:attribute>
<xsl:if test="not(empty($feedName))">
<xsl:choose>
<xsl:when test="$feedName eq 'kolcraft'">
<xsl:copy-of select="exsl:node-set(document('kolcraft-brands.xml'))" />
<xsl:copy-of select="exsl:node-set(document('kolcraft-categories.xml'))" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="document('contours-categories.xml')" />
</xsl:otherwise>
</xsl:choose>
<xsl:copy>
<xsl:apply-templates select="recordset" />
</xsl:copy>
</xsl:if>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="recordset">
<Products>
<xsl:for-each select="row">
<Product>
<xsl:attribute name="removed" select="'false'" />
<xsl:apply-templates select="@*|node()" />
</Product>
</xsl:for-each>
</Products>
</xsl:template>
<xsl:template match="F1">
<ExternalId><xsl:value-of select="." /></ExternalId>
</xsl:template>
<xsl:template match="F2">
<UPCs>
<UPC><xsl:value-of select="." /></UPC>
</UPCs>
</xsl:template>
<xsl:template match="F3">
<Name><xsl:value-of select="." /></Name>
</xsl:template>
<xsl:template match="F4">
<Description><xsl:value-of select="." /></Description>
</xsl:template>
<xsl:template match="F5">
<ProductPageUrl><xsl:value-of select="." /></ProductPageUrl>
</xsl:template>
<xsl:template match="F6">
<ImageUrl><xsl:value-of select="." /></ImageUrl>
</xsl:template>
<xsl:template match="F7">
<CategoryExternalId><xsl:value-of select="lower-case(normalize-space(replace(., '[/ ]', '-')))" /></CategoryExternalId>
</xsl:template>
<xsl:template match="fielddescription" />
</xsl:stylesheet>
There are 2 problems I'm having and I'm not sure why they happen:
1. <Brands>
& <Categories>
are getting an empty namespace when being imported
2. <dataroot_r00295>
continues to appear as the 1st child of the root <Feed>
.
Here's a snippet of the kind of source document its using:
<?xml version="1.0" encoding="ISO-8859-1"?>
<dataroot_r00295>
<fielddescription>
<F1>ExternalID</F1>
<F2>UPC</F2>
<F3>Name</F3>
<F4>Description</F4>
<F5>ProductPageUrl</F5>
<F6>ProductImageUrl</F6>
<F7>CategoryExternalID</F7>
</fielddescription>
<recordset>
<row>
<F1>ED003-QCX</F1>
<F2>031878025147</F2>
<F3>Sealy Naturals-Cotton Crib Mattress Pad</F3>
<F4>Give baby plush comfort from natural cotton fibers with the innovative Sealy Naturals-Cotton Crib Mattress Pad.</F4>
<F5>http://www.kolcraft.com/sealy-naturals-cotton-crib-mattress-pad.html</F5>
<F6>http://www.kolcraft.com/media/catalog/product/e/d/ed003-qcx-1_1_4.jpg</F6>
<F7>Bedding/Pads</F7>
</row>
</recordset>
</dataroot_r00295>
And here's a snippet of what it produces:
<?xml version="1.0" encoding="UTF-8"?>
<Feed extractDate="2016-05-05T19:32:27.863-05:00"
incremental="false"
name="kolcraft"
xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6">
<Brands xmlns="">
<Brand removed="false">
<ExternalId>brands</ExternalId>
<Name>Brands</Name>
<!--BrandPageUrl>http://www.kolcraft.com/brands.html</BrandPageUrl -->
</Brand>
</Brands>
<Categories xmlns="">
<Category removed="false">
<ExternalId>baby-products</ExternalId>
<Name>Baby Products</Name>
<CategoryPageUrl>http://www.kolcraft.com/baby-products.html</CategoryPageUrl>
</Category>
</Categories>
<dataroot_r00295 xmlns="">
<Products>
<Product removed="false">
<ExternalId>ED003-QCX</ExternalId>
<UPCs>
<UPC>031878025147</UPC>
</UPCs>
<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>bedding-pads</CategoryExternalId>
</Product>
</Products>
</dataroot_r00295>
</Feed>
Can anyone explain what's going wrong in my stylesheet? I'm stumped.
Also: If there's any other way to use templates more efficiently, please feel free to teach me the proper way to use XSLT.
In general, if you want to create an XML document where the result elements are supposed to be all in a certain namespace then the right and convenient approach is to put the namespace declaration for that namespace on the xsl:stylesheet
respectively xsl:transform
root element of the stylesheet, i.e.
<xsl:stylesheet
exclude-result-prefixes="exsl xs"
version="2.0"
xmlns:exsl="http://exslt.org/common"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6">
That way all result elements created in different templates will be in that namespace and even if you need to change that inside of a certain template you can then put an xmlns=""
there.
So that way you should get rid of the xmlns="''
appearing, unless they are produced by the documents you copy in. If those elements you copy in from other documents are in no namespace and you want them to be in the namespace http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6
then you can't copy them, instead you have to transform them using e.g. <xsl:apply-templates select="document('foo.xml')/node()"/>
where you set up templates that create elements in the namespace, assuming my earlier suggestion (with the xmlns="..."
on the xsl:stylesheet
) it suffices to have
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>