Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to get namespaces in scope from XmlReader

Tags:

c#

.net

xml

wcf

I need to implement serializable type for element which contains a sequence of any elements with XPath-like expressions. It has very simple scheme:

<xsd:complexType name="FilterType">
    <xsd:sequence>
        <xsd:any minOccurs="0" maxOccurs="unbounded" />
    </xsd:sequence>
</xsd:complexType>

The semantic of this element is described in WSBaseNotification topic 4.2. The problem is that to interpret an expression we need some mechanism to resolve prefixes that was used in it (XmlReader provide such functionality via LookupNamespace). But there is another problem that it is not possible to parse expression at this stage, we even can not make any assumptions about expression type and dialect at this moment. So we need somehow collect all defined prefixes in that scope. Some of XmlReader-s (for example XmlTextReader) implements interface IXmlNamespaceResolver which provide such functionality via GetNamespacesInScope but many of them didn't (for example XmlMtomReader). This type used in many web service requests, the web service use wcf framework and have several bindings, so we can not make any assumption about what XmlReader will be used. Here is prototype implementation of such type, if we have GetNamespacesInScope for XmlReader:

[Serializable]
public class FilterType : IXmlSerializable {
public XElement[] Any;
public void ReadXml(XmlReader reader) {
    var xelist = new LinkedList<XElement>();
    reader.Read();
    var dr = reader as XmlDictionaryReader;
    var gns = reader.GetNamespacesInScope(); // need to implement

    while (reader.NodeType != XmlNodeType.EndElement) {
        if (reader.NodeType == XmlNodeType.Element) {
            var x = XElement.ReadFrom(reader) as XElement;
            foreach (var ns in gns) {
                var pref = ns.Key;
                var uri = ns.Value;
                if (x.GetNamespaceOfPrefix(pref) == null) {
                    x.Add(new XAttribute(XName.Get(pref, "http://www.w3.org/2000/xmlns/"), uri));
                }
            }
            xelist.AddLast((XElement)x);
        } else {
            reader.Skip();
        }
    }
    Any = xelist.ToArray();
    reader.ReadEndElement();
}

public void WriteXml(XmlWriter writer) {
    if (Any != null) {
        foreach (var x in Any) {
            x.WriteTo(writer);
        }
    }
}

public XmlSchema GetSchema() {
    return null;
}
}

Is there any way to implement GetNamespacesInScope for every possible XmlReader? Or maybe there is another solution?

like image 262
andrey.ko Avatar asked Dec 11 '11 19:12

andrey.ko


People also ask

How to give namespace in Xsd?

Specifying a target namespace. The following XSD schema specifies a target namespace by using the xsd:targetNamespace attribute. The schema also sets the elementFormDefault and attributeFormDefault attribute values to "unqualified" (the default value for these attributes).

How to define namespace in XML?

XML Namespaces - The xmlns Attribute When using prefixes in XML, a namespace for the prefix must be defined. The namespace can be defined by an xmlns attribute in the start tag of an element. The namespace declaration has the following syntax. xmlns:prefix="URI".

What is target namespace in Xml Schema?

Figure 1: Elements and attributes in XML Schema namespace are used to write an XML Schema document, which generates elements and attributes as defined by user and puts them in {target namespace}. This {target namespace} is then used to validate the XML instance.

What is target namespace?

Most business and communications problems that XML can solve require a combination of several XML vocabularies. XML has a mechanism for qualifying names to be allocated into different namespaces, such as namespaces that apply to different industries.


2 Answers

I use the code like this :

        XPathDocument doc = new XPathDocument("catalog.xml");
        XPathNavigator nav = doc.CreateNavigator();
        var v = nav.GetNamespacesInScope(XmlNamespaceScope.All);

Hope it helps, Radu

like image 138
radu florescu Avatar answered Sep 22 '22 13:09

radu florescu


You may, however, need a namespace-manager - for example:

XmlElement el = ...; //TODO
XmlNamespaceManager nsmgr = new XmlNamespaceManager(
    el.OwnerDocument.NameTable);
nsmgr.AddNamespace("x", el.OwnerDocument.DocumentElement.NamespaceURI);
var nodes = el.SelectNodes(@"/x:outerelement/x:innerelement", nsmgr);
like image 27
MethodMan Avatar answered Sep 20 '22 13:09

MethodMan