【发布时间】:2011-12-11 19:04:05
【问题描述】:
我需要为元素实现可序列化类型,该类型包含具有类似 XPath 表达式的任何元素的序列。 它有非常简单的方案:
<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会使用什么做任何假设。
这是这种类型的原型实现,如果我们有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;
}
}
有没有办法为每个可能的XmlReader 实现GetNamespacesInScope?或者也许还有其他解决方案?
【问题讨论】:
-
您是否在创建 xmlreader 时“接收”它 - 让您可以选择将其包装在一个传递阅读器中,该阅读器跟踪命名空间并将包装器传递给将使用它的对象?
-
据我了解,一个 WCF 编码元素负责创建 xmlreader,可以不同,目前服务使用两种编码 TextMessageEncoding 和 MtomMessageEncoding,第一个使用 XmlUTF8TextReader,第二个使用 XmlMtomReader(在 .net 4.0 中)但不能保证这种行为将来不会改变,例如在 .net 4.5 中。在我看来,要控制创建 xmlreader,我们需要重写整个编码绑定元素,在我看来这是一项非常复杂的任务。