Skip to content

Commit

Permalink
Merge pull request #961 from ermshiperete/bug-xamarin-18118
Browse files Browse the repository at this point in the history
[System.XML] XSL bugfixes for #18118 #18114 #18113
  • Loading branch information
alexischr committed Apr 28, 2014
2 parents 7b48e45 + f01a48e commit 2d2d90e
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 7 deletions.
1 change: 1 addition & 0 deletions mcs/class/System.XML/Mono.Xml.Xsl.Operations/XslValueOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ protected override void Compile (Compiler c)
throw new XsltCompileException ("XSLT value-of element cannot contain any child.", null, c.Input);
}
} while (c.Input.MoveToNext ());
c.Input.MoveToParent ();
}
}

Expand Down
3 changes: 3 additions & 0 deletions mcs/class/System.XML/Mono.Xml.Xsl.Operations/XslVariable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,10 @@ public override void Evaluate (XslTransformProcessor p)

protected override object GetValue (XslTransformProcessor p)
{
p.PushNodeset (new SelfIterator (p.Root, p.XPathContext));
p.NodesetMoveNext ();
Evaluate (p);
p.PopNodeset ();
return p.globalVariableTable [this];
}

Expand Down
6 changes: 4 additions & 2 deletions mcs/class/System.XML/Mono.Xml.Xsl/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,13 @@ internal class Compiler : IStaticXsltContext {
bool keyCompilationMode;
string stylesheetVersion;
XsltDebuggerWrapper debugger;
bool strictMSXslNodeSet;

public Compiler (object debugger)
public Compiler (object debugger, bool strictMSXslNodeSet)
{
if (debugger != null)
this.debugger = new XsltDebuggerWrapper (debugger);
this.strictMSXslNodeSet = strictMSXslNodeSet;
}

public XsltDebuggerWrapper Debugger {
Expand Down Expand Up @@ -576,7 +578,7 @@ Expression IStaticXsltContext.TryGetFunction (QName name, FunctionArguments args
{
string ns = LookupNamespace (name.Namespace);
if (ns == XslStylesheet.MSXsltNamespace && name.Name == "node-set")
return new MSXslNodeSet (args);
return new MSXslNodeSet (strictMSXslNodeSet, args);

if (ns != "")
return null;
Expand Down
24 changes: 21 additions & 3 deletions mcs/class/System.XML/Mono.Xml.Xsl/XslFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
using System.Xml.XPath;
using System.Xml.Xsl;
using Mono.Xml.Xsl;
using Mono.Xml.XPath;

using QName = System.Xml.XmlQualifiedName;

Expand Down Expand Up @@ -649,13 +650,15 @@ public override object Evaluate (BaseIterator iter)

class MSXslNodeSet : XPathFunction
{
bool strict;
Expression arg0;

public MSXslNodeSet (FunctionArguments args) : base (args)
public MSXslNodeSet (bool strict, FunctionArguments args) : base (args)
{
if (args == null || args.Tail != null)
throw new XPathException ("element-available takes 1 arg");


this.strict = strict;
arg0 = args.Arg;
}

Expand All @@ -673,13 +676,28 @@ public override object Evaluate (BaseIterator iter)
{
XsltCompiledContext ctx = iter.NamespaceManager as XsltCompiledContext;
XPathNavigator loc = iter.Current != null ? iter.Current.Clone () : null;
XPathNavigator nav = arg0.EvaluateAs (iter, XPathResultType.Navigator) as XPathNavigator;
object val = arg0.Evaluate (iter);

XPathNavigator nav = val as XPathNavigator;
if (nav == null && !strict) {
var iterResult = val as XPathNodeIterator;
if (iterResult != null)
return iterResult;

var strResult = val as string;
if (strResult == string.Empty) {
DTMXPathDocumentWriter2 w = new DTMXPathDocumentWriter2 (ctx.Processor.Root.NameTable, 10);
nav = w.CreateDocument ().CreateNavigator ();
}
}

if (nav == null) {
if (loc != null)
return new XsltException ("Cannot convert the XPath argument to a result tree fragment.", null, loc);
else
return new XsltException ("Cannot convert the XPath argument to a result tree fragment.", null);
}

ArrayList al = new ArrayList ();
al.Add (nav);
return new ListIterator (al, ctx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ public void Load (string stylesheetUri, XsltSettings settings, XmlResolver style
private void Load (XPathNavigator stylesheet,
XsltSettings settings, XmlResolver stylesheetResolver)
{
s = new Compiler (debugger).Compile (stylesheet, stylesheetResolver, null);
s = new Compiler (debugger, false).Compile (stylesheet, stylesheetResolver, null);
}

#endregion
Expand Down
2 changes: 1 addition & 1 deletion mcs/class/System.XML/System.Xml.Xsl/XslTransform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public void Load (IXPathNavigable stylesheet, XmlResolver resolver, Evidence evi

public void Load (XPathNavigator stylesheet, XmlResolver resolver, Evidence evidence)
{
s = new Compiler (debugger).Compile (stylesheet, resolver, evidence);
s = new Compiler (debugger, true).Compile (stylesheet, resolver, evidence);
}

public void Load (XmlReader stylesheet, XmlResolver resolver, Evidence evidence)
Expand Down
1 change: 1 addition & 0 deletions mcs/class/System.XML/System.Xml_test.dll.sources
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,4 @@ System.Xml.Xsl/XsltCompileExceptionTests.cs
System.Xml.Xsl/XsltExceptionCas.cs
System.Xml.Xsl/XsltExceptionTests.cs
System.Xml.XPath/XPathExceptionCas.cs
System.Xml.Xsl/XslCompiledTransformTests.cs
112 changes: 112 additions & 0 deletions mcs/class/System.XML/Test/System.Xml.Xsl/XslCompiledTransformTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using NUnit.Framework;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;

namespace MonoTests.System.Xml.Xsl
{
[TestFixture]
public class XslCompiledTransformTests
{
[Test]
public void GlobalVariableReferencesAnotherGlobalVariable ()
{
string xsl = @"<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:variable name='global2'><xsl:value-of select='root/@attr' /></xsl:variable>
<xsl:variable name='global1'>
<xsl:for-each select='//foo'>
<xsl:if test='@attr = $global2'>
<xsl:value-of select='name(.)' />: <xsl:value-of select='@attr' />
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match='/'>
<root>
<xsl:value-of select='$global1' />
</root>
</xsl:template>
</xsl:stylesheet>";
StringWriter sw = new StringWriter ();
XslCompiledTransform t = new XslCompiledTransform ();
t.Load (new XPathDocument (new StringReader (xsl)));
t.Transform (new XPathDocument (new XmlTextReader (new StringReader ("<root attr='B'><foo attr='A'/><foo attr='B'/><foo attr='C'/></root>"))), null, sw);
Assert.AreEqual ("<?xml version=\"1.0\" encoding=\"utf-16\"?><root>foo: B</root>", sw.ToString ());
}

[Test]
public void MSXslNodeSetAcceptsNodeSet ()
{
string xsl = @"<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:msxsl='urn:schemas-microsoft-com:xslt'>
<xsl:template match='/'>
<root>
<!-- msxsl:node-set() accepts a node set -->
<xsl:for-each select='msxsl:node-set(root/foo)'>
<xsl:value-of select='name(.)' />: <xsl:value-of select='@attr' />
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>";
StringWriter sw = new StringWriter ();
XslCompiledTransform t = new XslCompiledTransform ();
t.Load (new XPathDocument (new StringReader (xsl)));
// should transform without an exception
t.Transform (new XPathDocument (new XmlTextReader (new StringReader ("<root><foo attr='A'/><foo attr='B'/><foo attr='C'/></root>"))), null, sw);
}

[Test]
public void MSXslNodeSetAcceptsEmptyString ()
{
string xsl = @"<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:msxsl='urn:schemas-microsoft-com:xslt'>
<xsl:template match='/'>
<root>
<!-- msxsl:node-set() accepts an empty string -->
<xsl:variable name='empty'></xsl:variable>
<xsl:for-each select='msxsl:node-set($empty)'>
<xsl:value-of select='name(.)' />: <xsl:value-of select='@attr' />
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>";
StringWriter sw = new StringWriter ();
XslCompiledTransform t = new XslCompiledTransform ();
t.Load (new XPathDocument (new StringReader (xsl)));
// should transform without an exception
t.Transform (new XPathDocument (new XmlTextReader (new StringReader ("<root><foo attr='A'/><foo attr='B'/><foo attr='C'/></root>"))), null, sw);
}

[Test]
public void ValueOfElementWithInsignificantWhitespace ()
{
string xsl = @"<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:template match='/'>
<root>
<bar>
<xsl:if test='root/@attr'>
<xsl:value-of select='root/@attr'>
</xsl:value-of>
</xsl:if>
</bar>
<baz>
<xsl:for-each select='root/foo'>
<xsl:if test='position() != 1'>
<xsl:text>,</xsl:text>
</xsl:if>
<xsl:value-of select='name(.)' />: <xsl:value-of select='@attr' />
</xsl:for-each>
</baz>
</root>
</xsl:template>
</xsl:stylesheet>";
StringWriter sw = new StringWriter ();
XslCompiledTransform t = new XslCompiledTransform ();
t.Load (new XmlTextReader(new StringReader(xsl)));
t.Transform (new XPathDocument (new XmlTextReader (new StringReader ("<root attr='D'><foo attr='A'/><foo attr='B'/><foo attr='C'/></root>"))), null, sw);
Assert.AreEqual ("<?xml version=\"1.0\" encoding=\"utf-16\"?><root><bar>D</bar><baz>foo: A,foo: B,foo: C</baz></root>", sw.ToString ());
}
}
}

0 comments on commit 2d2d90e

Please sign in to comment.