2009-09-17 2 views
4

Когда я загружаю XML-документ с диска в XDocument, XDocument имеет свойство BaseUri, имеющее только готовое свойство, которое содержит исходное местоположение документа XML на диске. Иными словами,Можно ли присвоить BaseUri XDocument?

XDocument doc = XDocument.Load(@"c:\temp\doc.xml"); 
Console.Out.WriteLine(doc.BaseUri); 
// Outputs "file:///c:/temp/doc.xml" 

Если я создаю новый XDocument с нуля, у него нет BaseUri. Например:

XDocument doc = new XDocument(new XElement("test")); 
Console.Out.WriteLine(doc.BaseUri); 
// Outputs nothing 

Можно ли присвоить этот новый XDocument BaseUri? Я хотел бы иметь возможность создавать новые документы, назначать им имена и легко передавать эти имена вместе с ними.

ответ

2

После прочтения LoadOptions.SetBaseUri очевидно, что LINQ to XML использует аннотации для достижения значения свойства BaseUri. Это печально, так как аннотация имеет внутренний тип System.Xml.Linq.BaseUriAnnotation, к которому у вас нет доступа. Мое предложение состояло бы в том, чтобы, возможно, задать свою собственную аннотацию, которая будет использовать либо ее значение, либо значение BaseUri, если оно не было null.

public class MyBaseUriAnnotation 
{ 
    public XObject XObject { get; private set; } 

    private string baseUri = String.Empty; 
    public string BaseUri 
    { 
     get 
     { 
      if (String.IsNullOrEmpty(this.baseUri)) 
       return this.XObject.BaseUri; 

      return this.baseUri; 
     } 

     set { this.baseUri = value; } 
    } 

    public MyBaseUriAnnotation(XObject xobject) 
     : this(xobject, String.Empty) 
    { 
    } 

    public MyBaseUriAnnotation(XObject xobject, string baseUri) 
    { 
     if (xobject == null) throw new ArgumentNullException("xobject"); 
     this.XObject = xobject; 
     this.baseUri = baseUri; 
    } 
} 

Вы можете использовать метод, чтобы добавить аннотацию к XDocument вы разбираете по своему усмотрению:

public static XDocument XDocumentFromString(string baseUri, string xml) 
{ 
    var xdoc = XDocument.Parse(xml); 
    xdoc.AddAnnotation(new MyBaseUriAnnotation(xdoc, baseUri)); 
    return xdoc; 
} 

И тогда, когда вы хотите, чтобы найти BaseUri, вы можете использовать расширение метод для получения правильного BaseUri:

public static string FindBaseUri(this XObject xobject) 
{ 
    if (xobject == null) throw new ArgumentNullException(xobject); 
    var baseUri = xobject.Annotation<MyBaseUriAnnotation>(); 
    return baseUri != null ? baseUri.BaseUri : xobject.BaseUri; 
} 
+0

Спасибо, я не думал об использовании аннотацию –

+0

Можно также расширить мой пример для поиска вверх. иерархию XObject, пока не найдет MyBaseUriAnnotation, чтобы вести себя идентично с XObject.BaseUri. – user7116

3

насколько я могу судить, вы не можете легко сделать это. Вы можете сделать это при загрузке любым XmlReader, если вы установите соответствующий параметр. Это означает, что вы может написать метод расширения, который сохранил его в MemoryStream, после чего загрузили новый документ из пользовательского класса, производного от XmlTextReader, который перегрузил BaseUri. Это было бы очень некрасиво, хотя :(

+0

Но это работает:/(для XmlDocument тоже). –

1

Уродливый, но самый быстрый способ:

var doc = XElement.Parse(someXml); 
doc.GetType() 
     .GetMethod("SetBaseUri", BindingFlags.NonPublic | BindingFlags.Instance) 
     .Invoke(doc, new object[] { "some uri" }); 
0
public class CustomXmlDocument : XmlDocument 
    { 
     public string CustomBaseURL { get; set; } 


     public override string BaseURI 
     { 
      get { return this.CustomBaseURL; } 
     } 
    } 

CustomXmlDocument objXML=new CustomXmlDocument(); 
objXML.CustomBaseURL="BaseURI"; 
objXML.loadXml(xml document); 
Смежные вопросы