trademark trademark - 2 months ago 13
C# Question

C# XSL Transformation Breaks Encoding

SOLVED
Long story short, don't use CDATA in your XSL transformation. Read on for details.

Background
Standard C# application saves an object to and XML file using the XmlSerializer. I need to grab that saved XML file, add the reference to the XSL transformation, apply said transformation, then save as .graphml

Problem
Currently my output seems to have improper encoding. The < and > signs are represented as "&lt" and "&gt" which is not valid graphml (or xml for that matter)

Details
Here is what the output file looks like at the moment:

<?xml version="1.0" encoding="utf-8"?>

&lt;graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"&gt;

&lt;graph id="G" edgedefault="undirected"&gt;

&lt;node id="n1"/&gt;

&lt;edge source="n1" target="n2"/&gt;

&lt;edge source="n1" target="n3"/&gt;

&lt;edge source="n1" target="n5"/&gt;

&lt;edge source="n1" target="n7"/&gt;

&lt;edge source="n1" target="n9"/&gt;

&lt;node id="n2"/&gt;

&lt;edge source="n2" target="n1"/&gt;

&lt;edge source="n2" target="n9"/&gt;


For what it's worth, I know that the XML that I'm transforming is valid (and in the proper format), and I know that the xsl file is valid and working properly because I can use it on other files just fine. Something about the way the XSL transformation is applied by C# is causing this issue. Here is the relevant code:

// Create an XML writer
XmlSerializer writer = new XmlSerializer(typeof(formattedMeshNet));

var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\netTransform.xml";
var transformPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\GraphFormatTransform.xsl";
var savePath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\ExportedNetwork.graphml";

System.IO.FileStream file = System.IO.File.Create(path);

writer.Serialize(file, saveMe);
file.Close();

// Add style sheet association
XmlDocument xDoc = new XmlDocument();
var transformAssn = xDoc.CreateProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"GraphFormatTransform.xsl\"");
xDoc.AppendChild(transformAssn);


// Load xml just saved
System.Xml.Xsl.XslCompiledTransform myXslTransform;

myXslTransform = new System.Xml.Xsl.XslCompiledTransform();

myXslTransform.Load(transformPath);
myXslTransform.Transform(path, savePath);


Any ideas would be appreciated! Feel free to ask nicely for details which will be happily provided if you see I've left out anything :)

Potentially related issue which didn't really tell me anything, but you might get something useful:
XSL transformation give me wrong encoding

I also tried doing what was suggested here:
The XslCompiledTransform output encoding

Thanks!

** EDIT **

Per request, here is the full XML document and associated XSL transformation

<?xml version="1.0"?>
<formattedMeshNet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<contents>
<node>
<nodeID>1</nodeID>
<physNeighbors>
<int>4</int>
<int>6</int>
<int>7</int>
<int>8</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>2</nodeID>
<physNeighbors>
<int>4</int>
<int>11</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>3</nodeID>
<physNeighbors>
<int>4</int>
<int>9</int>
<int>10</int>
<int>11</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>4</nodeID>
<physNeighbors>
<int>1</int>
<int>2</int>
<int>3</int>
<int>8</int>
<int>11</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>5</nodeID>
<physNeighbors>
<int>8</int>
<int>11</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>6</nodeID>
<physNeighbors>
<int>1</int>
<int>7</int>
<int>8</int>
<int>10</int>
<int>12</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>7</nodeID>
<physNeighbors>
<int>1</int>
<int>6</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>8</nodeID>
<physNeighbors>
<int>1</int>
<int>4</int>
<int>5</int>
<int>6</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>9</nodeID>
<physNeighbors>
<int>3</int>
<int>11</int>
<int>12</int>
<int>13</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>10</nodeID>
<physNeighbors>
<int>3</int>
<int>6</int>
<int>13</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>11</nodeID>
<physNeighbors>
<int>2</int>
<int>3</int>
<int>4</int>
<int>5</int>
<int>9</int>
<int>13</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>12</nodeID>
<physNeighbors>
<int>6</int>
<int>9</int>
</physNeighbors>
<visited />
<neighbors />
</node>
<node>
<nodeID>13</nodeID>
<physNeighbors>
<int>9</int>
<int>10</int>
<int>11</int>
</physNeighbors>
<visited />
<neighbors />
</node>
</contents>
</formattedMeshNet>




XSL




<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<![CDATA[
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">]]>

<![CDATA[<graph id="G" edgedefault="undirected">]]>
<xsl:for-each select="/formattedMeshNet/contents/node">
<xsl:variable name="parentNodeID">
<xsl:value-of select="nodeID" />
</xsl:variable>
<![CDATA[<node id="n]]><xsl:copy-of select="$parentNodeID" /><![CDATA["/>]]>
<xsl:for-each select="physNeighbors/int">
<![CDATA[<edge source="n]]><xsl:copy-of select="$parentNodeID" /><![CDATA[" target="n]]><xsl:value-of select="." /><![CDATA["/>]]>
</xsl:for-each>
</xsl:for-each>


<![CDATA[</graph>
</graphml>]]>
</xsl:template>
</xsl:stylesheet>

Answer

If I am guessing correctly, your stylesheet should look like this:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/formattedMeshNet">
    <graphml xmlns="http://graphml.graphdrawing.org/xmlns"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
     http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
        <graph id="G" edgedefault="undirected">
            <xsl:for-each select="contents/node">
                <xsl:variable name="parentNodeID" select="nodeID" /> 
                <node id="n{$parentNodeID}" />
                <xsl:for-each select="physNeighbors/int">
                    <edge source="n{$parentNodeID}" target="n{.}" />
                </xsl:for-each>
            </xsl:for-each>
        </graph>
     </graphml>
</xsl:template>

</xsl:stylesheet>

Applied to your input example, the result will be:

<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns      http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
   <graph id="G" edgedefault="undirected">
      <node id="n1"/>
      <edge source="n1" target="n4"/>
      <edge source="n1" target="n6"/>
      <edge source="n1" target="n7"/>
      <edge source="n1" target="n8"/>
      <node id="n2"/>
      <edge source="n2" target="n4"/>
      <edge source="n2" target="n11"/>
      <node id="n3"/>
      <edge source="n3" target="n4"/>
      <edge source="n3" target="n9"/>
      <edge source="n3" target="n10"/>
      <edge source="n3" target="n11"/>
      <node id="n4"/>
      <edge source="n4" target="n1"/>
      <edge source="n4" target="n2"/>
      <edge source="n4" target="n3"/>
      <edge source="n4" target="n8"/>
      <edge source="n4" target="n11"/>
      <node id="n5"/>
      <edge source="n5" target="n8"/>
      <edge source="n5" target="n11"/>
      <node id="n6"/>
      <edge source="n6" target="n1"/>
      <edge source="n6" target="n7"/>
      <edge source="n6" target="n8"/>
      <edge source="n6" target="n10"/>
      <edge source="n6" target="n12"/>
      <node id="n7"/>
      <edge source="n7" target="n1"/>
      <edge source="n7" target="n6"/>
      <node id="n8"/>
      <edge source="n8" target="n1"/>
      <edge source="n8" target="n4"/>
      <edge source="n8" target="n5"/>
      <edge source="n8" target="n6"/>
      <node id="n9"/>
      <edge source="n9" target="n3"/>
      <edge source="n9" target="n11"/>
      <edge source="n9" target="n12"/>
      <edge source="n9" target="n13"/>
      <node id="n10"/>
      <edge source="n10" target="n3"/>
      <edge source="n10" target="n6"/>
      <edge source="n10" target="n13"/>
      <node id="n11"/>
      <edge source="n11" target="n2"/>
      <edge source="n11" target="n3"/>
      <edge source="n11" target="n4"/>
      <edge source="n11" target="n5"/>
      <edge source="n11" target="n9"/>
      <edge source="n11" target="n13"/>
      <node id="n12"/>
      <edge source="n12" target="n6"/>
      <edge source="n12" target="n9"/>
      <node id="n13"/>
      <edge source="n13" target="n9"/>
      <edge source="n13" target="n10"/>
      <edge source="n13" target="n11"/>
   </graph>
</graphml>
Comments