【问题标题】:XmlReader to return node as-is without childrenXmlReader 按原样返回没有子节点的节点
【发布时间】:2011-09-15 17:25:20
【问题描述】:

我正在使用XmlReader 遍历一个大型 XML 文档,并将其拼接成一个更小且更易于管理的XmlDocmuent。在此过程中,我发现了一个有趣的节点,因此我要移动它:

        targetDoc.LoadXml("<result></result>");
        // Some interesting code removed
        using (XmlReader r = XmlReader.Create(file))
        {
            while (r.Read())
            {
                if (r.NodeType == XmlNodeType.Element)
                {
                    if (r.Name == match)
                    {
                        // Put the node into the target document
                        targetDoc.FirstChild.InnerXml = r.ReadOuterXml();
                        return targetDoc;
                    }
                }
             }
         }

这一切都很好,除了我想包含节点没有它的后代。我感兴趣的是节点本身及其属性。在这一点上,后代非常大,笨重且无趣。 (并且一次将它们全部读入内存会导致内存不足错误......)

是否有一种简单的方法可以将找到的元素的文本 (?) 及其属性(而不是其后代)获取到目标文档中?

【问题讨论】:

  • 你不应该使用new XmlTextReader()。请改用XmlReader.Create()
  • 它实际上是作为来自外部函数(未显示)的参数传递并为 SO 键入的。编辑所以希望我会得到一个有用的答案。
  • 试图帮助那些不知道比复制/粘贴他们在此处看到的代码更好的人。

标签: c# xml xmlreader


【解决方案1】:

我认为没有内置的方法可以做到这一点。我认为您必须自己读出属性和内容。

例如

static void Main(string[] args)
        {
            var xml = @"<root>
                                <parent a1 = 'foo' a2 = 'bar'>Some Parent text
                                    <child a3 = 'frob' a2= 'brob'> Some Child Text
                                    </child>
                                </parent>
            </root>";
            var file = new StringReader(xml) ;

            using (XmlReader r = XmlReader.Create(file))
            {
                while (r.Read())
                {
                    if (r.NodeType == XmlNodeType.Element)
                    {
                        if (r.Name == "parent")
                        {
                            var output = new StringBuilder();
                            var settings = new XmlWriterSettings();
                            settings.OmitXmlDeclaration = true;
                            using (var elementWriter = XmlWriter.Create(output, settings))
                            {   

                                elementWriter.WriteStartElement(r.Name);

                                elementWriter.WriteAttributes(r,false);
                                elementWriter.WriteValue(r.ReadString());
                                elementWriter.WriteEndElement();
                            }

                            Console.WriteLine(output.ToString());
                        }
                    }
                }
            }


            if (System.Diagnostics.Debugger.IsAttached)
                Console.ReadLine();

        }

会产生

<parent a1="foo" a2="bar">Some Parent text</parent>
Press any key to continue . . .

【讨论】:

    【解决方案2】:

    你可以试试 XmlNode.CloneNode(bool deep) 方法。

    deep: true 递归克隆指定节点下的子树; false 仅克隆节点本身。

    【讨论】:

    • 他没有要克隆的 XmlNode,因为后代太庞大了。
    【解决方案3】:

    不一定是好方法,但您可以读取字符串直到到达开始标记的末尾,然后手动附加结束标记并将其加载到 XmlDocument 中。

    编辑:

    这样想:

    string xml = r.ReadOuterXml();
    int firstEndTag = xml.IndexOf('>');
    int lastStartTag = xml.LastIndexOf('<');
    string newXml = xml.Substring(0, firstEndTag) + xml.Substring(lastStartTag);
    

    这可能根本无效,因为那里有一个大字符串。你的方法可能是最好的。两者都不漂亮,但考虑到您的限制,我个人想不出更好的方法(这并不是说不存在更好的方法)。

    【讨论】:

    • 我想到了类似的东西:if (r.HasAttributes) for (int i = 0; i &lt; r.AttributeCount; i++) { r.MoveToAttribute(i); atts[r.Name] = r.Value; // Dictionary&lt;string, string&gt; } 然后按照你的建议为节点重建 XML,但这看起来......很难看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多