Kann ich vordefinierten Namensraum verwenden, wenn das Laden eines XDocument?
-
22-08-2019 - |
Frage
Ich habe oft mit XML-Dokumenten umgehen, die Elemente enthalten Namespace, aber erklärt nicht den Namespace. Zum Beispiel:
<root>
<a:element/>
</root>
Da das Präfix „a“ wird nie ein Namespace-URI zugeordnet ist, ist das Dokument ungültig. Wenn ich lade solch ein XML-Dokument mit dem folgenden Code:
using (StreamReader reader = new StreamReader(new FileStream(inputFileName,
FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) {
doc = XDocument.Load(reader, LoadOptions.PreserveWhitespace);
}
es löst eine Ausnahme unter Angabe (zu Recht), dass das Dokument einen nicht deklarierten Namespace enthält und ist nicht wohlgeformt ist.
Also, ich kann Standard-Namespace-Präfix vordefinieren -> NamespaceURI Paare für den Parser zurückgreifen? XmlNamespaceManager sieht vielversprechend aus, aber nicht wissen, wie es zu dieser Situation anwenden (oder, wenn ich kann).
Lösung
Sie können eine XmlReader
mit einem XmlParserContext
erstellen, die über den Namensraum kennt; die folgenden Werke für XmlDocument
und XDocument
:
class SimpleNameTable : XmlNameTable {
List<string> cache = new List<string>();
public override string Add(string array) {
string found = cache.Find(s => s == array);
if (found != null) return found;
cache.Add(array);
return array;
}
public override string Add(char[] array, int offset, int length) {
return Add(new string(array, offset, length));
}
public override string Get(string array) {
return cache.Find(s => s == array);
}
public override string Get(char[] array, int offset, int length) {
return Get(new string(array, offset, length));
}
}
static void Main() {
XmlNamespaceManager mgr = new XmlNamespaceManager(new SimpleNameTable());
mgr.AddNamespace("a", "http://foo/bar");
XmlParserContext ctx = new XmlParserContext(null, mgr, null,
XmlSpace.Default);
using (XmlReader reader = XmlReader.Create(
new StringReader(@"<root><a:element/></root>"), null, ctx)) {
XDocument doc = XDocument.Load(reader);
//XmlDocument doc = new XmlDocument();
//doc.Load(reader);
}
}
Andere Tipps
Auf der Grundlage der vorherigen Antwort, können Sie die Namespacepräfixe durch erste Laden in ein XmlDocument und Parsen der OuterXml des XmlDocument in ein XDocument bewahren
XDocument LoadWithPrefix(Stream stream)
{
XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
mgr.AddNamespace("a", "http://foo/bar");
XmlParserContext ctx = new XmlParserContext(null, mgr, null, XmlSpace.Default);
using (XmlReader reader = XmlReader.Create(stream, null, ctx))
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
return XDocument.Parse(doc.OuterXml);
}
}