tags:

views:

118

answers:

2

I'm trying to transform one XML format to another using XSL. Try as I might, I can't seem to get a result.

I've hacked away at this for a while now and I've had no success. I'm not even getting any exceptions. I'm going to post the entire code and hopefully someone can help me work out what I've done wrong.

I'm aware there are likely to be problems in the xsl I have in terms of selects and matches, but I'm not fussed about that at the moment.

The output I'm getting is the input XML without any XML tags. The transformation is simply not occurring.


Here's my XML Document:

<?xml version="1.0"?>
<Transactions>
    <Account>
        <PersonalAccount>
            <AccountNumber>066645621</AccountNumber>
            <AccountName>A Smith</AccountName>
            <CurrentBalance>-200125.96</CurrentBalance>
            <AvailableBalance>0</AvailableBalance>
            <AccountType>LOAN</AccountType>
        </PersonalAccount>
    </Account>
    <StartDate>2010-03-01T00:00:00</StartDate>
    <EndDate>2010-03-23T00:00:00</EndDate>
    <Items>
        <Transaction>
            <ErrorNumber>-1</ErrorNumber>
            <Amount>12000</Amount>
            <Reference>Transaction 1</Reference>
            <CreatedDate>0001-01-01T00:00:00</CreatedDate>
            <EffectiveDate>2010-03-15T00:00:00</EffectiveDate>
            <IsCredit>true</IsCredit>
            <Balance>-324000</Balance>
        </Transaction>
        <Transaction>
            <ErrorNumber>-1</ErrorNumber>
            <Amount>11000</Amount>
            <Reference>Transaction 2</Reference>
            <CreatedDate>0001-01-01T00:00:00</CreatedDate>
            <EffectiveDate>2010-03-14T00:00:00</EffectiveDate>
            <IsCredit>true</IsCredit>
            <Balance>-324000</Balance>
        </Transaction>
    </Items>
</Transactions>

Here's my XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" />
  <xsl:param name="currentdate"></xsl:param>
  <xsl:template match="Transactions">

<xsl:element name="OFX">
    <xsl:element name="SIGNONMSGSRSV1">
        <xsl:element name="SONRS">
            <xsl:element name="STATUS">
                <xsl:element name="CODE">0</xsl:element>
                <xsl:element name="SEVERITY">INFO</xsl:element>
            </xsl:element>
            <xsl:element name="DTSERVER"><xsl:value-of select="$currentdate" /></xsl:element>
            <xsl:element name="LANGUAGE">ENG</xsl:element>
        </xsl:element>
    </xsl:element>
    <xsl:element name="BANKMSGSRSV1">
        <xsl:element name="STMTTRNRS">
            <xsl:element name="TRNUID">1</xsl:element>
            <xsl:element name="STATUS">
                <xsl:element name="CODE">0</xsl:element>
                <xsl:element name="SEVERITY">INFO</xsl:element>
            </xsl:element>
            <xsl:element name="STMTRS">
                <xsl:element name="CURDEF">AUD</xsl:element>
                <xsl:element name="BANKACCTFROM">
                    <xsl:element name="BANKID">RAMS</xsl:element>
                    <xsl:element name="ACCTID"><xsl:value-of select="Account/PersonalAccount/AccountNumber" /></xsl:element>
                    <xsl:element name="ACCTTYPE"><xsl:value-of select="Account/PersonalAccount/AccountType" /></xsl:element>
                </xsl:element>
                <xsl:element name="BANKTRANLIST">
                    <xsl:element name="DTSTART"><xsl:value-of select="StartDate" /></xsl:element>
                    <xsl:element name="DTEND"><xsl:value-of select="EndDate" /></xsl:element>

    <xsl:for-each select="Items/Transaction">
                    <xsl:element name="STMTTRN">
                        <xsl:element name="TRNTYPE"><xsl:choose><xsl:when test="IsCredit">CREDIT</xsl:when><xsl:otherwise>DEBIT</xsl:otherwise></xsl:choose></xsl:element>
                        <xsl:element name="DTPOSTED"><xsl:value-of select="EffectiveDate" /></xsl:element>
                        <xsl:element name="DTUSER"><xsl:value-of select="CreatedDate" /></xsl:element>
                        <xsl:element name="TRNAMT"><xsl:value-of select="Amount" /></xsl:element>
                        <xsl:element name="FITID" />
                        <xsl:element name="NAME"><xsl:value-of select="Reference" /></xsl:element>
                        <xsl:element name="MEMO"><xsl:value-of select="Reference" /></xsl:element>
                    </xsl:element>
    </xsl:for-each>

                </xsl:element>
                <xsl:element name="LEDGERBAL">
                    <xsl:element name="BALAMT"><xsl:value-of select="Account/PersonalAccount/CurrentBalance" /></xsl:element>
                    <xsl:element name="DTASOF"><xsl:value-of select="EndDate" /></xsl:element>
                </xsl:element>
            </xsl:element>
        </xsl:element>
    </xsl:element>
</xsl:element>
  </xsl:template>
</xsl:stylesheet>

Here's my method to transform my XML:

public string TransformToXml(XmlElement xmlElement, Dictionary<string, object> parameters)
{
    string strReturn = "";

    // Load the XSLT Document
    XslCompiledTransform xslt = new XslCompiledTransform();
    xslt.Load(xsltFileName);

    // arguments
    XsltArgumentList args = new XsltArgumentList();
    if (parameters != null && parameters.Count > 0)
    {
        foreach (string key in parameters.Keys)
        {
            args.AddParam(key, "", parameters[key]);
        }
    }

    //Create a memory stream to write to
    Stream objStream = new MemoryStream();

    // Apply the transform
    xslt.Transform(xmlElement, args, objStream);

    objStream.Seek(0, SeekOrigin.Begin);

    // Read the contents of the stream
    StreamReader objSR = new StreamReader(objStream);

    strReturn = objSR.ReadToEnd();

    return strReturn;
}

The contents of strReturn is an XML tag (<?xml version="1.0" encoding="utf-8"?>) followed by a raw dump of the contents of the original XML document, stripped of XML tags.

What am I doing wrong here?

+1  A: 

I found that I needed to couch my transformations in the following template:

<?xml version="1.0" encoding="UTF-8" ?>
<xslt:stylesheet version="1.0"
                 xmlns:xslt="http://www.w3.org/1999/XSL/Transform"&gt;
  <xslt:template match="child::*"
                 priority="-1000">
    <xslt:copy>
      <xslt:call-template name="dc_CopyAll" />
    </xslt:copy>
  </xslt:template>

  <xslt:template match="attribute::*"
                 priority="-1000">
    <xslt:attribute namespace="{namespace-uri()}"
                    name="{local-name()}">
      <xslt:value-of select="." />
    </xslt:attribute>
  </xslt:template>

  <xslt:template name="dc_CopyAll">
    <xslt:apply-templates select="attribute::*|child::*" />
  </xslt:template>

  <!-- your transforms would go here -->
</xslt:stylesheet>

The way this works is that there are low priority catch-all templates that trap every node and copy their content while executing the entire body of templates in the transform on each child node. Any template with a priority over -1000 will take precedence.

I honestly don't know if you are going to be helped by this but the problem has the same smell as the problem I was trying to solve when I wrote it.

Can you explain this a little more? What does it do and how do I use it? Where does my actual XSL go?
Damovisa
I'm going to be honest and point out that it has been, I think, four or maybe five years since I wrote this so be aware that this is possible stale. When I wrote it, I was working on a product that allowed people to write XSLTs that would transform _part_ of an XML tree. It solves the problem of copying stuff that was _not_ specified as being transformed while still transforming parts of an XML tree. In your case, you are starting at the top of the tree so this may or may not help but I thought it might be useful, if it does help. Use will be covered in a following comment.
Actually... I'll edit to show use.
+4  A: 

I have verified that the provided transformation when applied with XslCompiledTransform on the provided XML document produces very meaningful (probably the desired) output.

Let me guess: maybe the provided XML is not the same as the one used in practice? Maybe you have a default namespace?

If so, you need to match nodes in the default namespace -- not in "no namespace".

You can easily verify if the XmlElement that you provide is in a namespace: inspect/print its NamespaceURI property.

Dimitre Novatchev
It looks like this was exactly the problem. The XML did end up having a namespace. Once I defined that in the XSLT, everything worked fine.Thanks!
Damovisa
@Dimitre, bravo :-)
infant programmer
+1 for successful psychic debugging. :)
Tomalak
Thanks @Tomalak and @infant-programmer. Don't ask me in what namespace my dreams are ... :)
Dimitre Novatchev
Yes, psychic debugging was very helpful! Apologies for not putting this in the question - the serializer I was using to dump to a file (so I could paste) was leaving out namespaces. Examining the NamespaceURI property showed me there was actually one there.
Damovisa