1

A current problem I am trying to solve is generating a comparison of two xml files with differences and similarities via xslt.

For example the first xml file looks like

<?xml version="1.0" encoding="utf-8" ?>
<Stats Date="2011-01-01">
  <Player Rank="1">
    <GP>39</GP>
    <G>32</G>
    <A>33</A>
    <PlusMinus>20</PlusMinus>
    <PIM>29</PIM>
    <PP>10</PP>
    <SH>1</SH>
    <GW>3</GW>
    <Shots>0</Shots>
    <ShotPctg>154</ShotPctg>
    <TOIPerGame>20.8</TOIPerGame>
    <ShiftsPerGame>21:54</ShiftsPerGame>
    <FOWinPctg>22.6</FOWinPctg>
  </Player>
</Stats>

The second file looks like

<?xml version="1.0" encoding="utf-8" ?>
<Stats Date="2011-01-01">
  <Player Rank="2">
    <Name>John Smith</Name>
    <Team>NY</Team>
    <Pos>D</Pos>
    <GP>38</GP>
    <G>32</G>
    <A>33</A>
    <PlusMinus>15</PlusMinus>
    <PIM>29</PIM>
    <PP>10</PP>
    <SH>1</SH>
    <GW>4</GW>
    <Shots>0</Shots>
    <ShotPctg>158</ShotPctg>
    <TOIPerGame>20.8</TOIPerGame>
    <ShiftsPerGame>21:54</ShiftsPerGame>
    <FOWinPctg>22.6</FOWinPctg>
  </Player>
</Stats>

When I embed the second file into the xslt file the output works as expected:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="vrtfDoc2">
    <Stats Date="2011-01-01">
      <Player Rank="2">
        <Name>John Smith</Name>
        <Team>NY</Team>
        <Pos>D</Pos>
        <GP>38</GP>
        <G>32</G>
        <A>33</A>
        <PlusMinus>15</PlusMinus>
        <PIM>29</PIM>
        <PP>10</PP>
        <SH>1</SH>
        <GW>4</GW>
        <Shots>0</Shots>
        <ShotPctg>158</ShotPctg>
        <TOIPerGame>20.8</TOIPerGame>
        <ShiftsPerGame>21:54</ShiftsPerGame>
        <FOWinPctg>22.6</FOWinPctg>
      </Player>
    </Stats>
  </xsl:param>

  <xsl:variable name="vDoc2" select=
  "document('')/*/xsl:param[@name='vrtfDoc2']/*"/>

  <xsl:template match="node()|@*" name="identity">
    <xsl:param name="pDoc2"/>
    <xsl:copy>
      <xsl:apply-templates select="node()|@*">
        <xsl:with-param name="pDoc2" select="$pDoc2"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <xsl:apply-templates select="*">
      <xsl:with-param name="pDoc2" select="$vDoc2"/>
    </xsl:apply-templates>

    -----------------------

    <xsl:apply-templates select="$vDoc2">
      <xsl:with-param name="pDoc2" select="/*"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="Player/*">
    <xsl:param name="pDoc2"/>
    <xsl:if test=
   "not(. = $pDoc2/*/*[name()=name(current())])">
      <xsl:call-template name="identity"/>
    </xsl:if>
  </xsl:template>

  <xsl:template match="Name|Team|Pos" priority="20"/>
</xsl:stylesheet>

when using the following c# code:

private string Transform(string xml, string xml2, string xsl) {
            StringWriter writer = new StringWriter();
            XslCompiledTransform t = new XslCompiledTransform(true);
            XsltSettings settings = new XsltSettings(true, false);
            XmlTextReader xmlReader = new XmlTextReader(xml);

            XmlTextReader xslReader = new XmlTextReader(xsl);
            t.Load(xslReader, settings, null);

            t.Transform(xmlReader, null, writer);
            return writer.ToString();
        }

When I remove the embedded xml from the xslt

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="vrtfDoc2" />

  <xsl:variable name="vDoc2" select=
  "document('')/*/xsl:param[@name='vrtfDoc2']/*"/>

  <xsl:template match="node()|@*" name="identity">
    <xsl:param name="pDoc2"/>
    <xsl:copy>
      <xsl:apply-templates select="node()|@*">
        <xsl:with-param name="pDoc2" select="$pDoc2"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/">
    <xsl:apply-templates select="*">
      <xsl:with-param name="pDoc2" select="$vDoc2"/>
    </xsl:apply-templates>

    -----------------------

    <xsl:apply-templates select="$vDoc2">
      <xsl:with-param name="pDoc2" select="/*"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="Player/*">
    <xsl:param name="pDoc2"/>
    <xsl:if test=
   "not(. = $pDoc2/*/*[name()=name(current())])">
      <xsl:call-template name="identity"/>
    </xsl:if>
  </xsl:template>

  <xsl:template match="Name|Team|Pos" priority="20"/>
</xsl:stylesheet>

The change the c# method to

private string Transform(string xml, string xml2, string xsl) {
            StringWriter writer = new StringWriter();
            XslCompiledTransform t = new XslCompiledTransform(true);
            XsltSettings settings = new XsltSettings(true, false);
            XmlTextReader xmlReader = new XmlTextReader(xml);

            XmlDocument doc1 = new XmlDocument();
            // populate as needed e.g.
            doc1.Load(xml2);

            XmlTextReader xslReader = new XmlTextReader(xsl);
            t.Load(xslReader, settings, null);

            //Pass parameter value to xslt from code
            XsltArgumentList argumentList = new XsltArgumentList();
            argumentList.AddParam("vrtfDoc2", "", doc1);
            t.Transform(xmlReader, argumentList, writer);
            return writer.ToString();
        }

I get a blank output from the transform, for the life of me I can't understand why. I've stepped through both versions using the debugger and the parameter value looks identical in both occassions but when the parameter passed version hits the following snippet in the xslt no transform occurs:

<xsl:apply-templates select="$vDoc2">
      <xsl:with-param name="pDoc2" select="/*"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="Player/*">
    <xsl:param name="pDoc2"/>
    <xsl:if test=
   "not(. = $pDoc2/*/*[name()=name(current())])">
      <xsl:call-template name="identity"/>
    </xsl:if>
  </xsl:template>

Any help or suggestions would be much appeciated.

0

1 Answer 1

4

The problem is in this code:

  <xsl:param name="vrtfDoc2" />    

  <xsl:variable name="vDoc2" select=   
     "document('')/*/xsl:param[@name='vrtfDoc2']/*"/>

This parses the file that contains the XSLT stylesheet, locates the globa; xsl:param that has name attribute with string value "vrtfDoc2" and selects the children elements of this xsl:param -- however it has no children, therefore the value of $vDoc2 is the empty node-set.

Solution:

Use just:

<xsl:variable name="vDoc2" select="$vrtfDoc2/*"/>

Notes on naming:

Please rename the parameter as its current name is confusing and misleading:

  1. Use names starting with p for parameters and names starting with v for variables.

  2. A name like vrtfDoc2 usually means: this variable contains an RTF (and usually needs the xxx:node-set() function to be applied to it in order to produce a regular tree from it). However, this isn't the case in your case.

Therefore, a parameter name like: pDoc2 is more precise and informative.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.