Nicolas Pierre
Nicolas Pierre

Reputation: 1195

XSL Transformation not taking xml

I'm trying to transform an XML string with a XSL stylesheet. But for some reason he only takes my root element and not the rest. Something wibbly wobbly timey wimey probs but I can't see the issue..

I'll attach my code below.

XSL

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://foo.com/foo" xmlns:ns1="http://foo.com/foo" exclude-result-prefixes="ns1">
    <xsl:template match="/">
        <ns0:ProductionOrderRequests>
            <xsl:apply-templates select="ns1:ProductionOrderRequest" />
        </ns0:ProductionOrderRequests>
    </xsl:template>

    <xsl:template match="ns1:ProductionOrderRequest">
            <xsl:apply-templates select="ns1:ProductionOrderRequest" />
    </xsl:template>

    <xsl:template match="ns1:ProductionOrderRequest">
         <ProductionOrderRequest>
            <MESKey><xsl:value-of select="@MESKey" /></MESKey>
            <Material><xsl:value-of select="@Material" /></Material>
            <ProductionVersion><xsl:value-of select="@ProductionVersion" /></ProductionVersion>
            <Resource><xsl:value-of select="@Resource" /></Resource>
            <Plant><xsl:value-of select="@Plant" /></Plant>
            <OrderType><xsl:value-of select="@OrderType" /></OrderType>
            <StartDate><xsl:value-of select="@StartDate" /></StartDate>
            <StartTime><xsl:value-of select="@StartTime" /></StartTime>
            <EndDate></EndDate>
            <EndTime></EndTime>
            <TotalOrderQty><xsl:value-of select="@TotalOrderQty" /></TotalOrderQty>
         </ProductionOrderRequest>
    </xsl:template>
</xsl:stylesheet>

XML to transform

<?xml version="1.0" encoding="utf-8"?>
<ProductionOrderRequests xmlns:ns0="http://foo.com/foo">
    <ProductionOrderRequest>
        <MESKey>TblDatProduction_4017</MESKey>
        <Material>11596</Material>
        <ProductionVersion>0001</ProductionVersion>
        <Resource>60200001</Resource>
        <Plant>BE01</Plant>
        <OrderType>ZP76</OrderType>
        <StartDate>24-10-2008</StartDate>
        <StartTime>06:00:00</StartTime>
        <EndDate></EndDate>
        <EndTime></EndTime>
        <TotalOrderQty>1.00</TotalOrderQty>
    </ProductionOrderRequest>
</ProductionOrderRequests>

The C# class that represents the xml string.

[XmlRoot("ProductionOrderRequests", Namespace = "http://foo.com/foo")]
public class ProductionOrderRequests
{
    [XmlElement("ProductionOrderRequest")]
    public List<ProductionOrderRequest> ProductionOrderRequestCollection { get; set; }
}

[XmlRoot("ProductionOrderRequest")]
public class ProductionOrderRequest
{
    [XmlElement("MESKey")]
    public string MESKey { get; set; }
    [XmlElement("Material")]
    public int Material { get; set; }
    [XmlElement("ProductionVersion")]
    public string ProductionVersion { get; set; }
    [XmlElement("Resource")]
    public int Resource { get; set; }
    [XmlElement("Plant")]
    public string Plant { get; set; }
    [XmlElement("OrderType")]
    public string OrderType { get; set; }
    [XmlElement("StartDate")]
    public string StartDate { get; set; }
    [XmlElement("StartTime")]
    public string StartTime { get; set; }
    [XmlElement("EndDate")]
    public string EndDate { get; set; }
    [XmlElement("EndTime")]
    public string EndTime { get; set; }
    [XmlElement("TotalOrderQty")]
    public string TotalOrderQty { get; set; }
}

The function that preforms the transform

    public static string Transform(this string xmlString, string xslpath)
    {
        string output = String.Empty;
        try
        {
            StringReader rdr = new StringReader(xmlString);
            XPathDocument myXPathDoc = new XPathDocument(rdr);

            var myXslTrans = new XslCompiledTransform();

            myXslTrans.Load(xslpath);

            StringWriter sw = new StringWriter();
            XmlWriter xwo = XmlWriter.Create(sw);

            myXslTrans.Transform(myXPathDoc, null, xwo);
            output = sw.ToString();
            xwo.Close();
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: {0}", e.ToString());
        }
        return output;
    }

What I've tried

Upvotes: 0

Views: 114

Answers (1)

Tim C
Tim C

Reputation: 70618

You've got a couple of problems with your XSLT, but firstly, you may have a problem with your XML too. It starts off like so...

<ProductionOrderRequests xmlns:ns0="http://foo.com/foo">

You've declared a namespace, but are not actually using the prefix anywhere, which means ProductionOrderRequests and all the other elements are in no namespace. As your XSLT is looking for elements in namespaces, it won't match them. Possibly you mean to do this in your XML....

<ProductionOrderRequests xmlns="http://foo.com/foo">

(If not, then you don't need the respective namespace prefix in your XSLT).

As for the XSLT, you start off by doing this...

<xsl:template match="/">
    <ns0:ProductionOrderRequests>
        <xsl:apply-templates select="ns1:ProductionOrderRequest" />
    </ns0:ProductionOrderRequests>
</xsl:template>

But "/" matches the document node, not the root ProductionOrderRequests element, therefore where you do <xsl:apply-templates select="ns1:ProductionOrderRequest" /> it won't find anything, because ProductionOrderRequests is the child node in this case. It probably needs to be this....

<xsl:template match="/">
    <ns0:ProductionOrderRequests>
        <xsl:apply-templates select="ns1:ProductionOrderRequests" />
    </ns0:ProductionOrderRequests>
</xsl:template>

And then you have this template...

<xsl:template match="ns1:ProductionOrderRequest">
    <xsl:apply-templates select="ns1:ProductionOrderRequest" />
</xsl:template>

You are matching ProductionOrderRequest but then looking for a child of the same name. You probably mean to do this, to skip over the parent ProductionOrderRequests element.

<xsl:template match="ns1:ProductionOrderRequests">
    <xsl:apply-templates select="ns1:ProductionOrderRequest" />
</xsl:template>

Finally, you are outputting data like so...

<MESKey><xsl:value-of select="@MESKey" /></MESKey>

But the '@' prefix is used for attributes. Your XML contains elements, so it should be...

<MESKey><xsl:value-of select="ns1:MESKey" /></MESKey>

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://foo.com/foo" xmlns:ns1="http://foo.com/foo" exclude-result-prefixes="ns1">
<xsl:template match="/">
    <ns0:ProductionOrderRequests>
        <xsl:apply-templates select="ns1:ProductionOrderRequests" />
    </ns0:ProductionOrderRequests>
</xsl:template>

<xsl:template match="ns1:ProductionOrderRequests">
        <xsl:apply-templates select="ns1:ProductionOrderRequest" />
</xsl:template>

<xsl:template match="ns1:ProductionOrderRequest">
     <ProductionOrderRequest>
        <MESKey><xsl:value-of select="ns1:MESKey" /></MESKey>
        <Material><xsl:value-of select="ns1:Material" /></Material>
        <ProductionVersion><xsl:value-of select="ns1:ProductionVersion" /></ProductionVersion>
        <Resource><xsl:value-of select="ns1:Resource" /></Resource>
        <Plant><xsl:value-of select="ns1:Plant" /></Plant>
        <OrderType><xsl:value-of select="ns1:OrderType" /></OrderType>
        <StartDate><xsl:value-of select="ns1:StartDate" /></StartDate>
        <StartTime><xsl:value-of select="ns1:StartTime" /></StartTime>
        <EndDate></EndDate>
        <EndTime></EndTime>
        <TotalOrderQty><xsl:value-of select="ns1:TotalOrderQty" /></TotalOrderQty>
     </ProductionOrderRequest>
</xsl:template>
</xsl:stylesheet>

Upvotes: 5

Related Questions