954,517 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

XML to XML using XSLT through C#

Hi,

I've got an XML file that I need to make changes to before creating an output XML file.
I've got an XSLT Transform file which does part of the job fine, but I'm needing to go one step further which is where I'm struggling.

In C# I'm using an XslCompiledTransform object to trigger the transform task and this works fine for the part that works so far, but I'm stuck for where to go from here.

I need to get an attribute value from the XML back into C# which will be put through a separate C++ DLL to get another value which will be inserted into the XML as additional attributes in the same node. It is likely that they'll want to add further values in using the same technique in the future, so it needs to be adaptable.

From what I've read so far, I think I can use the xsl:message element to bounce something back, and I should be able to pick this up in C# as an event fired by the XslCompiledTransform object. But, how do I get the information back from C# into the XslCompiledTransform object in order to add it to the output XML as attributes in the right place.


Some of the files I'll be processing through can be in excess of 20k records, and the XML structure is pretty in-depth. I'm not too bothered about how quick it is as it'll be badged as a data conversion task (following updates to the application that uses the original files). I'm happy to trade off some speed to have code that is easier to maintain in the future.


Example Input XML:

<RootNode>
  <Person ID="1" Name="Bob Smith" Dept="Risks">
    <Address Number="12" PostCode="A12 3BC" Country="UK"/>
  </Person>
</RootNode>


Example Transform XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml"/>
  <xsl:template match="RootNode">
    <RootNode>
      <xsl:foreach select="Person">
        <Person>
          <xsl:copy-of select="@ID"/>
          <xsl:copy-of select="@Name"/>
          <xsl:copy-of select="@Dept"/>
          <xsl:foreach select="Address">
            <xsl:copy-of select="@Number"/>
            <!-- Need to take this PostCode value and pass back to C# -->
            <xsl:copy-of select="@PostCode"/>
            <!-- Based on what C# gets from the DLL, add the following attribute ("StreetName") if it doesn't already exist -->
            <xsl:choose>
              <xsl:when test="StreetName">
                <xsl:copy-of select="@StreetName"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:attribute name="StreetName">
                  <xsl:value-of select="Test Road"/>
                </xsl:attribute>
              </xsl:otherwise>
            </xsl:choose>
            <xsl:copy-of select="@Country"/>
          </xsl:foreach>
        </Person>
      </xsl:foreach>
    </RootNode>
  </xsl:template>
</xsl:stylesheet>


Expected output XML:

<RootNode>
  <Person ID="1" Name="Bob Smith" Dept="Risks">
    <Address Number="12" PostCode="A12 3BC" StreetName="Test Road" Country="UK"/>
  </Person>
</RootNode>


In the above examples, I'm hoping to pass the PostCode back to C#, get the StreetName from a C++ DLL (by looking up the PostCode) and then pass the value back into the XSLT for adding to the XML.

Can anyone help?

Thanks in advance,
Jon

jonifen
Junior Poster
152 posts since Nov 2007
Reputation Points: 13
Solved Threads: 17
 

OK, I did a bit more searching after posting the above, and rephrased my google search criteria and found the following URL: http://projects.ischool.washington.edu/tabrooks/545/ContentManagement/PassingParameters.htm

My problem is solved by following the above link. Basically, I was thinking in the wrong direction as in I was thinking C# would do the leg work, but in fact it's the other way around.

I followed the instructions and came up with the following:

In my C# project, I added a new class and added the method "getStreetName" (with the PostCode as a parameter) that calls to the C++ DLL and gets the response which I then use as a return value.

I then passed the object into the XslCompiledTransform object as an argument.

C# code:

using System;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;

private runXMLTrans(string xmlInPath, string xsltPath, string xmlOutPath)
{
  XsltArgumentList xslArg = new XsltArgumentList();
  addressQuery addressQueryObj = new addressQuery();
  xslArg.AddExtensionObject("urn:addressfinder", addressQueryObj);

  XslCompiledTransform xslTrans = new XslCompiledTransform();
  XPathDocument xPathDoc = new XPathDocument(xmlInPath);
  XmlTextWriter writer = new XmlTextWriter(xmlOutPath, null);

  try
  {
    xslTrans.Load(xsltPath);
    xslTrans.Transform(xPathDoc, xslArg, writer);
    return "Success";
  }
  catch (Exception ex)
  {
    return ex.Message.ToString();
  }

  writer.Close();
}


Along with the following XSLT Transform file:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:myObj="urn:addressfinder">
  <xsl:output method="xml"/>
  <xsl:template match="RootNode">
    <RootNode>
      <xsl:foreach select="Person">
        <Person>
          <xsl:copy-of select="@ID"/>
          <xsl:copy-of select="@Name"/>
          <xsl:copy-of select="@Dept"/>
          <xsl:foreach select="Address">
            <xsl:copy-of select="@Number"/>
            <xsl:copy-of select="@PostCode"/>
            <xsl:choose>
              <xsl:when test="StreetName">
                <xsl:copy-of select="@StreetName"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:attribute name="StreetName">
                  <xsl:value-of select="myObj:getStreetName(PostCode)"/>
                </xsl:attribute>
              </xsl:otherwise>
            </xsl:choose>
            <xsl:copy-of select="@Country"/>
          </xsl:foreach>
        </Person>
      </xsl:foreach>
    </RootNode>
  </xsl:template>
</xsl:stylesheet>


Gives me the results I was after!

Problem solved :)

jonifen
Junior Poster
152 posts since Nov 2007
Reputation Points: 13
Solved Threads: 17
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You