2014-04-23 4 views
0

XDocument에서 XElement의 xpath를 알아야합니다. 네임 스페이스는 XDocument에서 나중에 참조 할 때 필요합니다.Xpath of 네임 스페이스

현재 예제를 Get the XPath to an XElement?에서 사용하고 있으며 네임 스페이스가없는 문서에서는 정상적으로 작동합니다. 하지만 네임 스페이스가있는 xml 문서가 아니며이를 지원하는 도구는 올바른 경로를 제공하지 않습니다.

예를 들어 내가 경로로 가정되는 방법

var x = XDocument.Load(@"file.xml"); 
var path = x.Elements().First().GetAbsoluteXPath(); 
var element = x.XPathSelectElement(path); 

XPathSelectElement에 XML 경로가 /:Report로 찾아 낼 것입니다 문서

<?xml version="1.0" encoding="utf-8"?> 
<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition"> 
    <AutoRefresh>0</AutoRefresh> 
    <DataSources> 

다음 코드와 충돌이? 수동으로 "/ rd : Report"를 시도했지만 여전히 요소를 선택하지 못했습니다. 다른 주제에서 발견

확장자 : 당신의 사용 기능은 그 경로를 만드는 경우

public static class XExtensions 
{ 
    /// <summary> 
    /// Get the absolute XPath to a given XElement, including the namespace. 
    /// (e.g. "/a:people/b:person[6]/c:name[1]/d:last[1]"). 
    /// </summary> 
    public static string GetAbsoluteXPath(this XElement element) 
    { 
     if (element == null) 
     { 
      throw new ArgumentNullException("element"); 
     } 

     Func<XElement, string> relativeXPath = e => 
     { 
      int index = e.IndexPosition(); 

      var currentNamespace = e.Name.Namespace; 

      string name; 
      if (currentNamespace == null) 
      { 
       name = e.Name.LocalName; 
      } 
      else 
      { 
       string namespacePrefix = e.GetPrefixOfNamespace(currentNamespace); 
       name = namespacePrefix + ":" + e.Name.LocalName; 
      } 

      // If the element is the root, no index is required 
      return (index == -1) ? "/" + name : string.Format 
      (
       "/{0}[{1}]", 
       name, 
       index.ToString() 
      ); 
     }; 

     var ancestors = from e in element.Ancestors() 
         select relativeXPath(e); 

     return string.Concat(ancestors.Reverse().ToArray()) + 
       relativeXPath(element); 
    } 

    /// <summary> 
    /// Get the index of the given XElement relative to its 
    /// siblings with identical names. If the given element is 
    /// the root, -1 is returned. 
    /// </summary> 
    /// <param name="element"> 
    /// The element to get the index of. 
    /// </param> 
    public static int IndexPosition(this XElement element) 
    { 
     if (element == null) 
     { 
      throw new ArgumentNullException("element"); 
     } 

     if (element.Parent == null) 
     { 
      return -1; 
     } 

     int i = 1; // Indexes for nodes start at 1, not 0 

     foreach (var sibling in element.Parent.Elements(element.Name)) 
     { 
      if (sibling == element) 
      { 
       return i; 
      } 

      i++; 
     } 

     throw new InvalidOperationException 
      ("element has been removed from its parent."); 
    } 
} 
+0

http://stackoverflow.com/questions/585812/using-xpath-with-default-namespace-in-c-sharp의 가능한 복제본 – CSharpie

+0

여기서'.GetAbsoluteXPath()'는 어디에서 왔습니까? 어디에서나 찾을 수 없습니다 – Jehof

+0

@Jehof 질문에 추가했습니다. – Androme

답변

2

음, 우선 /:Report의 유효한 XPath 식 아닙니다 그것을 않는 경우에 출력하지 유효한 XPath를 XML 문서의 기본 네임 스페이스는 xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition"입니다. 실제로 입력과 같은 기본 네임 스페이스 선언이 주어지면 경로를 만드는 함수는 접두사 (물론 다른 네임 스페이스에 대해 여러 개)를 생성하고 기본 네임 스페이스 URI에 바인드해야합니다. 또는 다른 접근 방법을 사용하여 *[local-name() = 'Report' and namespace-uri() = 'http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition'] 양식의 단계를 생성해야합니다. 접두사의 생성과 네임 스페이스 URI에 대한 바인딩은 XPath 1.0에서 사용하는 특정 XPath API에 따라 다르지만 다른 접근 방식은 XPath API와 함께 작동합니다.