如何从XmlReader获得范围内的命名空间

问题描述:

我需要为元素实现可序列化的类型,其中包含具有类似XPath表达式的任何元素的序列。 这是一个非常简单的方案:如何从XmlReader获得范围内的命名空间

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

语义元素浓缩于WSBaseNotification话题4.2描述。 问题是,为了解释表达式,我们需要一些机制来解析在其中使用的前缀(XmlReader通过LookupNamespace提供这样的功能)。但还有另一个问题,现阶段不可能解析表达,我们现在甚至不能对表情类型和方言做出任何假设。所以我们需要以某种方式收集该范围内的所有已定义的前缀。某些XmlReader-s(例如XmlTextReader)实现了接口IXmlNamespaceResolver,它们通过GetNamespacesInScope提供了此类功能,但其中很多都没有(例如XmlMtomReader)。这种类型在许多Web服务请求中使用,Web服务使用wcf框架并有几个绑定,所以我们不能对使用什么XmlReader做任何假设。 这里是原型实现这种类型的,如果我们有XmlReaderGetNamespacesInScope

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

有什么办法来实现GetNamespacesInScope每一个可能的XmlReader?或者也许有另一种解决方案?

+0

你在创建它的地方“接收”xmlreader--给你选择将它包装在一个传递阅读器中,该阅读器跟踪名称空间并将包装器传递给将使用它的东西? –

+1

在我的理解中,一个WCF编码元素负责创建xmlreader,它可以是不同的,当前服务使用两个编码TextMessageEncoding和MtomMessageEncoding,第一个使用XmlUTF8TextReader,第二个使用XmlMtomReader(使用.net 4.0),但是没有保证行为将来不会改变,例如在.net 4.5中。在我看来,为了控制创建xmlreader,我们需要重写整个编码绑定元素,在我看来,这是一项非常复杂的任务。 –

我用这样的代码:

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

希望它能帮助, 拉杜

您可能,但是,需要一个命名空间管理器 - 例如:

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