XsltCompiledTransform question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • =?Utf-8?B?TWFyaw==?=

    XsltCompiledTransform question

    Here are three things that I thought would be equivalent but are not. Just
    wondering why:

    XmlElement foo = doc.CreateEleme nt("foo");
    // load it up with a body
    xslt.Transform (foo, null, new XmlTextWriter(n ew StringWriter()) );
    xslt.Transform (foo.CreateNavi gator(), null, new XmlTextWriter(n ew
    StringWriter()) );
    xslt.Transform( new XmlNodeReader(f oo), new XmlTextWriter(n ew StringWriter()) );

    Only the third one applies the transform and produces the expected output.
    The first two produce nothing.

    The docs say that passing in an XmlNode or navigator "usually an XmlDocument
    or an XPathDocument"; it doesn't say the transform won't be applied *unless*
    it's an XmlDocument.

    I understand the XmlNodeReader is hiding the fact that it's starting at
    something other than a document root.

    I know this is an peculiar use case but was curious why the first 2 produced
    nothing?

    Thanks
    Mark

  • Martin Honnen

    #2
    Re: XsltCompiledTra nsform question

    Mark wrote:
    Here are three things that I thought would be equivalent but are not. Just
    wondering why:
    >
    XmlElement foo = doc.CreateEleme nt("foo");
    // load it up with a body
    xslt.Transform (foo, null, new XmlTextWriter(n ew StringWriter()) );
    xslt.Transform (foo.CreateNavi gator(), null, new XmlTextWriter(n ew
    StringWriter()) );
    xslt.Transform( new XmlNodeReader(f oo), new XmlTextWriter(n ew StringWriter()) );
    >
    Only the third one applies the transform and produces the expected output.
    The first two produce nothing.
    >
    The docs say that passing in an XmlNode or navigator "usually an XmlDocument
    or an XPathDocument"; it doesn't say the transform won't be applied *unless*
    it's an XmlDocument.
    >
    I understand the XmlNodeReader is hiding the fact that it's starting at
    something other than a document root.
    >
    I know this is an peculiar use case but was curious why the first 2 produced
    nothing?
    I am sure you can pass in an XmlElement node or an XPathNavigator
    created from an XmlElement.
    For instance when XSLTFile1.xslt is the identity transformation

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:styleshe et version="1.0"
    xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@* | node()">
    <xsl:copy>
    <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
    </xsl:template>
    </xsl:stylesheet>

    then the following code

    XslCompiledTran sform xsltProc = new XslCompiledTran sform();
    xsltProc.Load(@ "..\..\XSLTFile 1.xslt");

    XmlDocument doc = new XmlDocument();
    XmlElement foo = doc.CreateEleme nt("foo");

    xsltProc.Transf orm(foo, null, Console.Out);
    Console.WriteLi ne();

    xsltProc.Transf orm(foo.CreateN avigator(), null, Console.Out);
    Console.WriteLi ne();

    outputs

    <?xml version="1.0" encoding="ibm85 0"?><foo />
    <?xml version="1.0" encoding="ibm85 0"?><foo />

    It is not clear to me how your sample code checks any output if you
    simply pass in new XmlTextWriter(n ew StringWriter()) as the third
    argument to the Transform method. Where would you see the transformation
    result in that case?

    --

    Martin Honnen --- MVP XML

    Comment

    • =?Utf-8?B?TWFyaw==?=

      #3
      Re: XsltCompiledTra nsform question

      Hi Martin,

      I was summarizing before; I really had
      StringWriter sw = new StringWriter();
      StringBuilder sb = sw.GetStringBui lder();
      so I could check the output.

      The issue is probably my stylesheet.
      <xsl:template match="/foo">

      When I pass in a dangling node, it's not matching the /. When I use an
      XmlNodeReader, it can't tell the difference...

      Thanks
      Mark

      "Martin Honnen" wrote:
      Mark wrote:
      Here are three things that I thought would be equivalent but are not. Just
      wondering why:

      XmlElement foo = doc.CreateEleme nt("foo");
      // load it up with a body
      xslt.Transform (foo, null, new XmlTextWriter(n ew StringWriter()) );
      xslt.Transform (foo.CreateNavi gator(), null, new XmlTextWriter(n ew
      StringWriter()) );
      xslt.Transform( new XmlNodeReader(f oo), new XmlTextWriter(n ew StringWriter()) );

      Only the third one applies the transform and produces the expected output.
      The first two produce nothing.

      The docs say that passing in an XmlNode or navigator "usually an XmlDocument
      or an XPathDocument"; it doesn't say the transform won't be applied *unless*
      it's an XmlDocument.

      I understand the XmlNodeReader is hiding the fact that it's starting at
      something other than a document root.

      I know this is an peculiar use case but was curious why the first 2 produced
      nothing?
      >
      I am sure you can pass in an XmlElement node or an XPathNavigator
      created from an XmlElement.
      For instance when XSLTFile1.xslt is the identity transformation
      >
      <?xml version="1.0" encoding="UTF-8" ?>
      <xsl:styleshe et version="1.0"
      xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
      <xsl:template match="@* | node()">
      <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
      </xsl:template>
      </xsl:stylesheet>
      >
      then the following code
      >
      XslCompiledTran sform xsltProc = new XslCompiledTran sform();
      xsltProc.Load(@ "..\..\XSLTFile 1.xslt");
      >
      XmlDocument doc = new XmlDocument();
      XmlElement foo = doc.CreateEleme nt("foo");
      >
      xsltProc.Transf orm(foo, null, Console.Out);
      Console.WriteLi ne();
      >
      xsltProc.Transf orm(foo.CreateN avigator(), null, Console.Out);
      Console.WriteLi ne();
      >
      outputs
      >
      <?xml version="1.0" encoding="ibm85 0"?><foo />
      <?xml version="1.0" encoding="ibm85 0"?><foo />
      >
      It is not clear to me how your sample code checks any output if you
      simply pass in new XmlTextWriter(n ew StringWriter()) as the third
      argument to the Transform method. Where would you see the transformation
      result in that case?
      >
      --
      >
      Martin Honnen --- MVP XML

      >

      Comment

      • Martin Honnen

        #4
        Re: XsltCompiledTra nsform question

        Mark wrote:
        I was summarizing before; I really had
        StringWriter sw = new StringWriter();
        StringBuilder sb = sw.GetStringBui lder();
        so I could check the output.
        >
        The issue is probably my stylesheet.
        <xsl:template match="/foo">
        >
        When I pass in a dangling node, it's not matching the /. When I use an
        XmlNodeReader, it can't tell the difference...
        The XmlNodeReader reparses the DOM so it makes some sense that it
        presents the foo element as a child of the root node /.
        For the other two cases (passing in the sole XmlElement or the
        XPathNavigator created on the sole XmlElement) the foo element has no
        root so your match="/foo" does not apply.
        Obviously it is an edge case but if you can change your stylesheet to
        make sure you use match="foo" it should work as needed.



        --

        Martin Honnen --- MVP XML

        Comment

        • Steven Cheng [MSFT]

          #5
          Re: XsltCompiledTra nsform question

          Hi Mark,

          I think your analysis is reasonable. The document root based path (
          "/....") make a single node not be able to be resolved. While using
          XmlNodeReader, it internally generate a document for the given XmlNode
          which makes the difference.

          Sincerely,

          Steven Cheng

          Microsoft MSDN Online Support Lead


          Delighting our customers is our #1 priority. We welcome your comments and
          suggestions about how we can improve the support we provide to you. Please
          feel free to let my manager know what you think of the level of service
          provided. You can send feedback directly to my manager at:
          msdnmg@microsof t.com.

          =============== =============== =============== =====
          Get notification to my posts through email? Please refer to
          Find official documentation, practical know-how, and expert guidance for builders working and troubleshooting in Microsoft products.

          ications.
          =============== =============== =============== =====
          This posting is provided "AS IS" with no warranties, and confers no rights.

          --------------------
          >From: =?Utf-8?B?TWFyaw==?= <mmodrall@nospa m.nospam>
          >References: <9A461CA0-60F3-4653-BB20-065A8F554510@mi crosoft.com>
          <elqDW5WzIHA.24 08@TK2MSFTNGP04 .phx.gbl>
          >Subject: Re: XsltCompiledTra nsform question
          >Date: Fri, 13 Jun 2008 10:02:00 -0700
          >
          >Hi Martin,
          >
          >I was summarizing before; I really had
          >StringWriter sw = new StringWriter();
          >StringBuilde r sb = sw.GetStringBui lder();
          >so I could check the output.
          >
          >The issue is probably my stylesheet.
          <xsl:template match="/foo">
          >
          >When I pass in a dangling node, it's not matching the /. When I use an
          >XmlNodeReade r, it can't tell the difference...
          >
          >Thanks
          >Mark
          >
          >"M

          Comment

          • =?Utf-8?B?TWFyaw==?=

            #6
            Re: XsltCompiledTra nsform question

            Hi Martin...

            I know this is wandering a bit afield, but after this discussion I got
            curious how the xpath operations on XmlNodes would respond, so I made a
            little test:

            XmlDocument selTest = new XmlDocument();
            XmlElement selElm;
            selTest.LoadXml ("<foo><a><b><c ><b>hi</b></c></b></a></foo>");
            XmlNodeList selList = selTest.SelectN odes("//b");
            selElm = selTest.Documen tElement.FirstC hild as XmlElement;
            selList = selElm.SelectNo des("//b");
            selList = selList[0].SelectNodes("//b");
            selElm = selTest.CreateE lement("d");
            selElm.InnerXml = "<b>in d</b>";
            selList = selElm.SelectNo des("//b");

            In this case, I was trying the "anywhere in tree" selection. I tried it on
            the document root, a couple of elements down, and then in a dangling element.

            Within the dom tree, I get the same 2 nodes no matter what node I make the
            selection from.

            From our prior discussion, I didn't know what to expect from the dangling
            node. In the case of the dangling (unrooted) element, selecting "//b"
            essentially treated the dangling node as the root and found the child.

            Is this a fundamentally different case that the one we talked about before?

            Thanks
            Mark

            Comment

            • Martin Honnen

              #7
              Re: XsltCompiledTra nsform question

              Mark wrote:
              From our prior discussion, I didn't know what to expect from the dangling
              node. In the case of the dangling (unrooted) element, selecting "//b"
              essentially treated the dangling node as the root and found the child.
              >
              Is this a fundamentally different case that the one we talked about before?
              The results astonish me.

              Here is a test:

              XmlDocument doc = new XmlDocument();

              XmlElement foo = doc.CreateEleme nt("foo");
              foo.InnerXml = "<bar>baz</bar>";

              XmlNode rootNode = foo.SelectSingl eNode("/");
              Console.WriteLi ne("rootNode.No deType: {0}; LocalName: {1}",
              rootNode.NodeTy pe, rootNode.LocalN ame);

              XPathNavigator fooNav = foo.CreateNavig ator();
              XPathNavigator rootNav = fooNav.SelectSi ngleNode("/");
              Console.WriteLi ne("rootNav.Nod eType: {0}; LocalName: {1}",
              rootNav.NodeTyp e, rootNav.LocalNa me);

              Output for me with Visual Studio 2005:

              rootNode.NodeTy pe: Element; LocalName: foo
              rootNav.NodeTyp e: Element; LocalName: foo


              So for the XPath API the dangling element node has itself as its root
              node selected by the XPath "/". If you select "/*" then you get the
              'bar' element as

              XmlDocument doc = new XmlDocument();

              XmlElement foo = doc.CreateEleme nt("foo");
              foo.InnerXml = "<bar>baz</bar>";

              XmlNode rootElement = foo.SelectSingl eNode("/*");
              Console.WriteLi ne("rootElement .NodeType: {0}; LocalName:
              {1}", rootElement.Nod eType, rootElement.Loc alName);

              XPathNavigator fooNav = foo.CreateNavig ator();
              XPathNavigator rootElNav = fooNav.SelectSi ngleNode("/*");
              Console.WriteLi ne("rootElNav.N odeType: {0}; LocalName:
              {1}", rootElNav.NodeT ype, rootElNav.Local Name);

              outputs

              rootElement.Nod eType: Element; LocalName: bar
              rootElNav.NodeT ype: Element; LocalName: bar


              That "/" selects an element node is rather odd in my view.

              --

              Martin Honnen --- MVP XML

              Comment

              • =?Utf-8?B?TWFyaw==?=

                #8
                Re: XsltCompiledTra nsform question

                I was scratching my head as well. Our resident xpath/xslt guru here saw
                "//b" as "descendent or self" which the XmlNode.SelectN odes() was decidedly
                not doing as well. With my first doc, I got the same 2 results no matter
                which node I started with, so it was running back up to the root and then
                traversing down.

                Given the behavior we saw in xslt with dangling nodes, I was surprised to
                find the XmlNode.SelectN odes() behaving it ways that seemed quite
                inconsistent with that...

                Thanks
                Mark


                "Martin Honnen" wrote:
                Mark wrote:
                >
                From our prior discussion, I didn't know what to expect from the dangling
                node. In the case of the dangling (unrooted) element, selecting "//b"
                essentially treated the dangling node as the root and found the child.

                Is this a fundamentally different case that the one we talked about before?
                >
                The results astonish me.
                >
                Here is a test:
                >
                XmlDocument doc = new XmlDocument();
                >
                XmlElement foo = doc.CreateEleme nt("foo");
                foo.InnerXml = "<bar>baz</bar>";
                >
                XmlNode rootNode = foo.SelectSingl eNode("/");
                Console.WriteLi ne("rootNode.No deType: {0}; LocalName: {1}",
                rootNode.NodeTy pe, rootNode.LocalN ame);
                >
                XPathNavigator fooNav = foo.CreateNavig ator();
                XPathNavigator rootNav = fooNav.SelectSi ngleNode("/");
                Console.WriteLi ne("rootNav.Nod eType: {0}; LocalName: {1}",
                rootNav.NodeTyp e, rootNav.LocalNa me);
                >
                Output for me with Visual Studio 2005:
                >
                rootNode.NodeTy pe: Element; LocalName: foo
                rootNav.NodeTyp e: Element; LocalName: foo
                >
                >
                So for the XPath API the dangling element node has itself as its root
                node selected by the XPath "/". If you select "/*" then you get the
                'bar' element as
                >
                XmlDocument doc = new XmlDocument();
                >
                XmlElement foo = doc.CreateEleme nt("foo");
                foo.InnerXml = "<bar>baz</bar>";
                >
                XmlNode rootElement = foo.SelectSingl eNode("/*");
                Console.WriteLi ne("rootElement .NodeType: {0}; LocalName:
                {1}", rootElement.Nod eType, rootElement.Loc alName);
                >
                XPathNavigator fooNav = foo.CreateNavig ator();
                XPathNavigator rootElNav = fooNav.SelectSi ngleNode("/*");
                Console.WriteLi ne("rootElNav.N odeType: {0}; LocalName:
                {1}", rootElNav.NodeT ype, rootElNav.Local Name);
                >
                outputs
                >
                rootElement.Nod eType: Element; LocalName: bar
                rootElNav.NodeT ype: Element; LocalName: bar
                >
                >
                That "/" selects an element node is rather odd in my view.
                >
                --
                >
                Martin Honnen --- MVP XML

                >

                Comment

                • Steven Cheng [MSFT]

                  #9
                  Re: XsltCompiledTra nsform question

                  Hi Mark,

                  I think the different behavior in XmlNode.Select with "//b" like path might
                  be caused by the difference context between XmlNode and XmlDocument. Since
                  XmlDocument has an entireo DOM context(start from root). And the "//b" like
                  path may also require a search from root to all descendent nodes.

                  Sincerely,

                  Steven Cheng

                  Microsoft MSDN Online Support Lead


                  Delighting our customers is our #1 priority. We welcome your comments and
                  suggestions about how we can improve the support we provide to you. Please
                  feel free to let my manager know what you think of the level of service
                  provided. You can send feedback directly to my manager at:
                  msdnmg@microsof t.com.

                  =============== =============== =============== =====
                  Get notification to my posts through email? Please refer to
                  Find official documentation, practical know-how, and expert guidance for builders working and troubleshooting in Microsoft products.

                  ications.

                  =============== =============== =============== =====
                  This posting is provided "AS IS" with no warranties, and confers no rights.
                  --------------------
                  >Thread-Topic: XsltCompiledTra nsform question
                  >thread-index: AcjQnqeS97g6+D1 NSG+IYJh/7hksDQ==
                  >X-WBNR-Posting-Host: 65.55.21.8
                  >From: =?Utf-8?B?TWFyaw==?= <mmodrall@nospa m.nospam>
                  >References: <9A461CA0-60F3-4653-BB20-065A8F554510@mi crosoft.com>
                  <elqDW5WzIHA.24 08@TK2MSFTNGP04 .phx.gbl<85E372 C4-C273-4C72-
                  >
                  >I was scratching my head as well. Our resident xpath/xslt guru here saw
                  >"//b" as "descendent or self" which the XmlNode.SelectN odes() was
                  decidedly
                  >not doing as well. With my first doc, I got the same 2 results no matter
                  >which node I started with, so it was running back up to the root and then
                  >traversing down.
                  >
                  >Given the behavior we saw in xslt with dangling nodes, I was surprised to
                  >find the XmlNode.SelectN odes() behaving it ways that seemed quite
                  >inconsistent with that...
                  >
                  >Thanks
                  >Mark
                  >
                  >
                  >"Martin Honnen" wrote:
                  >
                  >Mark wrote:
                  >>
                  From our prior discussion, I didn't know what to expect from the
                  dangling
                  node. In the case of the dangling (unrooted) element, selecting "//b"
                  essentially treated the dangling node as the root and found the child.
                  >
                  Is this a fundamentally different case that the one we talked about
                  before?
                  >>
                  >The results astonish me.
                  >>
                  >Here is a test:
                  >>
                  > XmlDocument doc = new XmlDocument();
                  >>
                  > XmlElement foo = doc.CreateEleme nt("foo");
                  > foo.InnerXml = "<bar>baz</bar>";
                  >>
                  > XmlNode rootNode = foo.SelectSingl eNode("/");
                  > Console.WriteLi ne("rootNode.No deType: {0}; LocalName: {1}",
                  >rootNode.NodeT ype, rootNode.LocalN ame);
                  >>
                  > XPathNavigator fooNav = foo.CreateNavig ator();
                  > XPathNavigator rootNav = fooNav.SelectSi ngleNode("/");
                  > Console.WriteLi ne("rootNav.Nod eType: {0}; LocalName: {1}",
                  >rootNav.NodeTy pe, rootNav.LocalNa me);
                  >>
                  >Output for me with Visual Studio 2005:
                  >>
                  >rootNode.NodeT ype: Element; LocalName: foo
                  >rootNav.NodeTy pe: Element; LocalName: foo
                  >>
                  >>
                  >So for the XPath API the dangling element node has itself as its root
                  >node selected by the XPath "/". If you select "/*" then you get the
                  >'bar' element as
                  >>
                  > XmlDocument doc = new XmlDocument();
                  >>
                  > XmlElement foo = doc.CreateEleme nt("foo");
                  > foo.InnerXml = "<bar>baz</bar>";
                  >>
                  > XmlNode rootElement = foo.SelectSingl eNode("/*");
                  > Console.WriteLi ne("rootElement .NodeType: {0}; LocalName:
                  >{1}", rootElement.Nod eType, rootElement.Loc alName);
                  >>
                  > XPathNavigator fooNav = foo.CreateNavig ator();
                  > XPathNavigator rootElNav = fooNav.SelectSi ngleNode("/*");
                  > Console.WriteLi ne("rootElNav.N odeType: {0}; LocalName:
                  >{1}", rootElNav.NodeT ype, rootElNav.Local Name);
                  >>
                  >outputs
                  >>
                  >rootElement.No deType: Element; LocalName: bar
                  >rootElNav.Node Type: Element; LocalName: bar
                  >>
                  >>
                  >That "/" selects an element node is rather odd in my view.
                  >>
                  >--
                  >>
                  > Martin Honnen --- MVP XML
                  > http://JavaScript.FAQTs.com/
                  >>
                  >

                  Comment

                  Working...