我正在尝试在XPathExpression对象中使用Microsoft XPath扩展函数(例如ms:string-compare http://msdn.microsoft.com/en-us/library/ms256114.aspx)。
这些函数是MSXML库中的扩展,如果我在XslCompiledTransform中使用它们(只是添加“ms”命名空间),它们就像魅力一样:
var xsl =
@"
<?xml version=""1.0"" encoding=""UTF-8""?>
<xsl:stylesheet version=""2.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
xmlns:xs=""http://www.w3.org/2001/XMLSchema""
xmlns:fn=""http://www.w3.org/2005/xpath-functions""
xmlns:ms=""urn:schemas-microsoft-com:xslt"">
<xsl:output method=""xml"" version=""1.0"" encoding=""UTF-8"" indent=""yes""/>
<xsl:template match=""/Data"">
<xsl:element name=""Result"">
<xsl:value-of select=""ms:string-compare(@timeout1, @timeout2)""/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>";
var xslDocument = new XmlDocument();
xslDocument.LoadXml(xsl);
var transform = new XslCompiledTransform();
transform.Load(xslDocument);
然后我尝试在XPathExpression中使用它们:
XPathNavigator nav = document.DocumentElement.CreateNavigator();
XPathExpression expr = nav.Compile("ms:string-compare(/Data/@timeout1, /Data/@timeout2)");
XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable);
manager.AddNamespace("ms", "urn:schemas-microsoft-com:xslt");
expr.SetContext(manager);
nav.Evaluate(expr);
但我得到一个例外“由于函数未知,此查询需要XsltContext”。
XsltContext是一个特定的XmlNamespaceManager,但我不知道是否可以在没有实际的XslCompiledTransform(它是抽象的)的情况下实例化它并将其用作我的表达式上下文。
有没有办法做到这一点(或者在XPathExpression中使用ms:扩展的任何其他方式)?
答案 0 :(得分:5)
这些ms前缀函数不包含在.net framework dom类中。你需要创建自定义函数来做同样的事情。
您可以使用以下示例代码;
string xpath = "my:string-compare('1','1)";
System.Xml.XmlNamespaceManager nsManager = new XsltContext();
nav.Select(xpath, nsManager );
或
XPathExpression compiledXPath = XPathExpression.Compile(xpath);
compiledXPath.SetContext(nsManager);
nav.Evaluate(compiledXPath);
你需要这些课程;
public class XsltContext : System.Xml.Xsl.XsltContext
{
public XsltContext()
{
Initialize();
}
public XsltContext(System.Xml.NameTable nameTable)
: base(nameTable)
{
Initialize();
}
private void Initialize()
{
RegisterFunction("my", "string-compare", typeof(StringCompare));
}
public override string LookupNamespace(string prefix)
{
return base.LookupNamespace(prefix);
}
public override int CompareDocument(string baseUri, string nextbaseUri)
{
return string.CompareOrdinal(baseUri, nextbaseUri);
}
public override bool PreserveWhitespace(System.Xml.XPath.XPathNavigator node)
{
return false;
}
public void RegisterFunction(string prefix, string name, Type function)
{
if (function == null)
throw new ArgumentNullException("function");
if (name == null)
throw new ArgumentNullException("name");
functions[prefix + ":" + name] = function;
}
Dictionary<string, Type> functions = new Dictionary<string, Type>();
public override System.Xml.Xsl.IXsltContextFunction ResolveFunction(string prefix, string name, System.Xml.XPath.XPathResultType[] argTypes)
{
Type functionType = null;
if (functions.TryGetValue(prefix + ":" + name, out functionType))
{
System.Xml.Xsl.IXsltContextFunction function = Activator.CreateInstance(functionType) as System.Xml.Xsl.IXsltContextFunction;
return function;
}
return null;
}
public override System.Xml.Xsl.IXsltContextVariable ResolveVariable(string prefix, string name)
{
return null;
}
public override bool Whitespace
{
get
{
return false;
}
}
internal static string GetValue(object v)
{
if (v == null)
return null;
if (v is System.Xml.XPath.XPathNodeIterator)
{
foreach (System.Xml.XPath.XPathNavigator n in v as System.Xml.XPath.XPathNodeIterator)
return n.Value;
}
return Convert.ToString(v);
}
}
class StringCompare : System.Xml.Xsl.IXsltContextFunction
{
public System.Xml.XPath.XPathResultType[] ArgTypes
{
get
{
return new System.Xml.XPath.XPathResultType[]
{
System.Xml.XPath.XPathResultType.String,
System.Xml.XPath.XPathResultType.String,
System.Xml.XPath.XPathResultType.String
};
}
}
public object Invoke(System.Xml.Xsl.XsltContext xsltContext, object[] args, System.Xml.XPath.XPathNavigator docContext)
{
string arg1 = XsltContext.GetValue(args[0]);
string arg2 = XsltContext.GetValue(args[1]);
string locale = "en-US";
if (args.Length > 2)
locale = XsltContext.GetValue(args[2]);
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.GetCultureInfo(locale);
return string.Compare(arg1, arg2, false, culture);
}
public int Maxargs
{
get
{
return 3;
}
}
public int Minargs
{
get
{
return 2;
}
}
public System.Xml.XPath.XPathResultType ReturnType
{
get
{
return System.Xml.XPath.XPathResultType.Number;
}
}
}
答案 1 :(得分:3)
您可以使用已编译的XPath,或使用Linqtoxml和XElement动态:
XPathCustomContext context = new XPathCustomContext(new NameTable());
context.AddNamespace("windward", XPathCustomContext.Namespace);
XmlDocument document = new XmlDocument();
string records = @"
<records>
<record id=""m""/>
<record id=""M""/>
<record id=""l""/>
</records>
";
document.LoadXml(records);
string xpath = @"//record[my:string-compare(@id,""m"")]";
//solution 1
XPathExpression compiledXPath = XPathExpression.Compile(xpath, context);
compiledXPath.SetContext(context);
XPathNavigator nav = document.CreateNavigator();
object res = nav.Evaluate(compiledXPath);
//solution 2
XElement elm = XElement.Parse(records);
IEnumerable<XElement> targets = elm.XPathSelectElements(xpath, context);
我的比较功能:
public class MyStringCompare : IWindwardContextFunction
{
public System.Xml.XPath.XPathResultType[] ArgTypes
{
get
{
return new System.Xml.XPath.XPathResultType[]
{
System.Xml.XPath.XPathResultType.String,
System.Xml.XPath.XPathResultType.String,
System.Xml.XPath.XPathResultType.String
};
}
}
/// <summary>
/// The function name.
/// </summary>
public string FunctionName
{
get { return "string-compare"; }
}
public object Invoke(System.Xml.Xsl.XsltContext xsltContext, object[] args, System.Xml.XPath.XPathNavigator docContext)
{
string arg1 = "";// Convert.ToString(args[0]);
object arg1Obj = args[0];
IEnumerable list = arg1Obj as IEnumerable;
if (arg1Obj != null)
{
IEnumerator listit = list.GetEnumerator();
listit.MoveNext();
XPathNavigator nav = (XPathNavigator)listit.Current;
arg1 = nav.Value;
}
string arg2 = Convert.ToString(args[1]);
string locale = "en-US";
if (args.Length > 2)
locale = Convert.ToString(args[2]);
System.Globalization.CultureInfo culture = CultureInfo.GetCultureInfo(locale);
return string.Compare(arg1, arg2, true) == 0;
}
public int Maxargs
{
get
{
return 3;
}
}
public int Minargs
{
get
{
return 2;
}
}
public System.Xml.XPath.XPathResultType ReturnType
{
get
{
return System.Xml.XPath.XPathResultType.Number;
}
}
}