2010-02-23 11 views
8

Bir XPathExpression nesnesinde Microsoft XPath Extension İşlevlerini (ms: string-karşılaştırması http://msdn.microsoft.com/en-us/library/ms256114.aspx) kullanmaya çalışıyorum.XPathExpression İçinde ms: xpath işlevlerini kullanma

Bu işlevler MSXML kütüphane içinde uzantıları vardır ve ben bir XslCompiledTransform bunları kullanırsanız onlar Acayip işe (basitçe "msn" ad ekleme): Sonra

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); 

Bir bunları kullanarak çalıştı 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); 

Ama bir istisna olsun "XsltContext çünkü bilinmeyen bir fonksiyonun bu sorgu için gereklidir".

XsltContext, belirli bir XmlNamespaceManager'tır, ancak gerçek bir XslCompiledTransform (özet) olmadan bunu gerçekleştirmenin mümkün olup olmadığını ve bunu benim ifade bağlamım olarak kullanıp kullanamayacağımı bilmiyorum.

Bunu yapmak için herhangi bir yolu var mı (veya bir XPathExpression içinde ms: uzantıları kullanmak için başka bir yol)?

+2

Mümkün edilebilir bir çözüm bekliyordum, ama bazıları sonra arama sizin için bir teklif buldum. Bu benim kendi değil, ben yorum olarak eklemek istiyorum [quote] Ne yazık ki XPathNavigator MIcrosoft ms: extention işlevlerini desteklemiyor, sadece XSLT bağlamında kullanılabilir. Bu uzantı işlevlerini XPathNavigator içine kancalamak için kullanabileceğiniz bir örnek kodu için http://www.tkachenko.com/blog/archives/000649.html adresine bakın. Oleg Tkachenko [XML MVP, MCPD] [endquote] Yani, kendi cevabım değil, yine de kullanabileceğiniz bir şey düşünüyorum. –

+0

çok teşekkürler ... Bir şekilde bir XsltContext elde etmeyi umuyordum, ama bunu geçersiz kılmak ve tüm soyut yöntemleri uygulamak tek yol gibi görünüyor :-( – Filini

cevap

5

Bu ms öneki işlevleri .net framework dom sınıflarına dahil değildir. Aynı şeyi yapmak için özel işlevlerinizi oluşturmanız gerekir.

Aşağıdaki örnek kodu kullanabilirsiniz;

string xpath = "my:string-compare('1','1)"; 

System.Xml.XmlNamespaceManager nsManager = new XsltContext(); 

nav.Select(xpath, nsManager); 

veya

XPathExpression compiledXPath = XPathExpression.Compile(xpath); 

compiledXPath.SetContext(nsManager); 

nav.Evaluate(compiledXPath); 

bu sınıflara gerekir; işlevini karşılaştırmak

 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); 

My:

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; 
     } 
    } 
} 
3

Sen Linqtoxml ve XElement ile derlenmiş XPath veya dinamik kullanabilirsiniz

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; 
     } 
    } 
}