Can I assign a BaseUri to an XDocument?

眉间皱痕 提交于 2020-01-13 02:13:23

问题


When I load an XML document from disk into an XDocument, that XDocument has a ready-only property BaseUri that contains the original XML document's location on disk. In other words,

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

If I create a new XDocument from scratch, it has no BaseUri. For example:

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

Can I assign this new XDocument a BaseUri? I'd like to be able to generate new documents, assign them names, and easily pass those names along with them.


回答1:


After reading LoadOptions.SetBaseUri it is apparent that LINQ to XML uses Annotations to achieve the setting of the BaseUri property. This is unfortunate as the annotation is of the internal type System.Xml.Linq.BaseUriAnnotation, which you do not have access to. My suggestion would be to perhaps set your own annotation which would use either its value or the value of BaseUri if it was not 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;
    }
}

You can then use a method to add the annotation to an XDocument you parse on your own:

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

And then whenever you'd like to find the BaseUri, you could use an extension method to retrieve the correct 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;
}



回答2:


As far as I can tell, you can't easily do so. You can do it when you load with any XmlReader, if you set the appropriate option. This means you could write an extension method which saved it to a MemoryStream then loaded a new document from a custom class derived from XmlTextReader which overrode BaseUri. That would be pretty ugly though :(




回答3:


The ugly but the fastest way:

var doc = XElement.Parse(someXml);
doc.GetType()
         .GetMethod("SetBaseUri", BindingFlags.NonPublic | BindingFlags.Instance)
         .Invoke(doc, new object[] { "some uri" });



回答4:


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


来源:https://stackoverflow.com/questions/1440023/can-i-assign-a-baseuri-to-an-xdocument

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!