簡體   English   中英

設置 InnerXml 時如何更改或繼承默認命名空間

[英]How to change or inherit the default namespace when setting InnerXml

當設置具有默認命名空間的XmlElementInnerXml時,所有沒有顯式命名空間的標簽都被解析為好像它們具有xmlns="" ,而不是繼承該XmlElement的默認命名空間(這是在解析真正的 XML 文檔時發生的情況)。

我的問題是:如何將復雜的 XML 字符串解析為文檔片段並將其分配給XmlElement ,並在解析該字符串時繼承目標XmlElement的命名空間前綴、默認命名空間等?

免責聲明:

  • 我完全了解 XML 命名空間是什么,以及XmlElement.InnerXml關於 XML 命名空間的確切行為是什么。 我不是在問為什么XmlElement.InnerXml正在做它目前所做的事情,或者這種行為是好是壞 我問我是否可以改變這種行為或使用其他一些技術來實現我上面描述的。
  • 我正在實現某種 XML 模板系統,它允許用戶將一些相當復雜的 XML 字符串作為片段插入到另一個 XML 文檔中。 要求用戶始終使用顯式命名空間是很瘋狂的(編寫冗余命名空間聲明的開銷很容易破壞模板的好處)。 我想要一種方法來解析它們並將生成的片段插入到主文檔中,就好像它們實際上是復制並粘貼到目標中一樣。
  • 我知道可以使用純 DOM 操作(如XmlDocument.CreateElement )保留默認命名空間,但我不想手動實現 XML 解析器並將 XML 字符串轉換為 DOM 操作
  • 也不想做“序列化整個 XML 文檔,進行字符串操作,然后將其解析”之類的事情。

可能嗎?

正如Martin Honnen評論以及Gideon Engelberth回答中提到的,加載 XDocument 時我可以使用預定義的命名空間嗎? ,您可以在通過XmlReader解析 XML 時使用XmlParserContext為命名空間(包括默認命名空間)預定義一個值。 使用配置了適當上下文的XmlReader ,您可以將內部 XML 直接加載到XmlElement中,並從其范圍繼承任何所需的命名空間。

要僅繼承默認命名空間,請創建以下擴展方法:

public static partial class XmlNodeExtensions
{
    public static void SetInnerXmlAndInheritDefaultNamespace(this XmlElement xmlElement, string innerXml)
    {
        using (var textReader = new StringReader(innerXml))
            xmlElement.SetInnerXmlAndInheritDefaultNamespace(textReader);
    }
    
    public static void SetInnerXmlAndInheritDefaultNamespace(this XmlElement xmlElement, TextReader innerTextReader)
    {
        XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
        mgr.AddNamespace("", xmlElement.GetNamespaceOfPrefix(""));
        XmlParserContext ctx = new XmlParserContext(null, mgr, null, XmlSpace.Default);
        using (var reader = XmlReader.Create(innerTextReader, new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment, CloseInput = false }, ctx))
        using (var writer = xmlElement.CreateNavigator().AppendChild())
        {
            writer.WriteNode(reader, true);
        }
    }
}

要繼承所有命名空間(您的問題中的要求並不完全清楚),請創建以下內容:

public static partial class XmlNodeExtensions
{
    public static void SetInnerXmlAndInheritNamespaces(this XmlElement xmlElement, string innerXml)
    {
        using (var textReader = new StringReader(innerXml))
            xmlElement.SetInnerXmlAndInheritNamespaces(textReader);
    }
    
    public static void SetInnerXmlAndInheritNamespaces(this XmlElement xmlElement, TextReader innerTextReader)
    {
        XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
        var navigator = xmlElement.CreateNavigator();
        foreach (var pair in navigator.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml))
            mgr.AddNamespace(pair.Key, pair.Value);
        XmlParserContext ctx = new XmlParserContext(null, mgr, null, XmlSpace.Default);
        using (var writer = navigator.AppendChild())
        using (var reader = XmlReader.Create(innerTextReader, new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment, CloseInput = false }, ctx))
        {
            writer.WriteNode(reader, true);
        }
    }
}

假設xmlElement是您想要插入innerXml字符串的現有XmlElement ,您可以執行以下操作:

xmlElement.SetInnerXmlAndInheritDefaultNamespace(innerXml);

例如,如果您的 XML 文檔看起來像:

<Root xmlns="defaultNameSpace" xmlns:d="dataNodeNamespace"><d:Data></d:Data></Root>

然后將以下 XML 添加到<d:Data>

<ElementToAdd Id="10101"><InnerValue>my inner value</InnerValue></ElementToAdd><ElementToAdd Id="20202"><InnerValue>another inner value</InnerValue></ElementToAdd>

結果將是:

<Root xmlns="defaultNameSpace" xmlns:d="dataNodeNamespace">
  <d:Data>
    <ElementToAdd Id="10101">
      <InnerValue>my inner value</InnerValue>
    </ElementToAdd>
    <ElementToAdd Id="20202">
      <InnerValue>another inner value</InnerValue>
    </ElementToAdd>
  </d:Data>
</Root>

演示小提琴herehere

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM