XmlReader для возврата узла как есть без дочерних элементов

Я просматриваю большой XML-документ, используя XmlReader, и сшиваю его в гораздо меньший и более управляемый 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;
                    }
                }
             }
         }

Это все хорошо, за исключением того, что я хотел бы включить узел без его потомков. Меня интересует сам узел с его атрибутами. Потомки очень крупные, громоздкие и неинтересные на данный момент. (И одновременное чтение их в память приведет к ошибкам нехватки памяти...)

Есть ли простой способ получить текст (?) найденного элемента с его атрибутами, но не его потомками, в целевой документ?


person Clinton Pierce    schedule 15.09.2011    source источник
comment
Вы не должны использовать new XmlTextReader(). Вместо этого используйте XmlReader.Create().   -  person John Saunders    schedule 15.09.2011
comment
На самом деле он был передан в качестве аргумента из внешней функции (не показана) и введен для SO. Отредактировано, так что, надеюсь, вместо этого я получу полезный ответ.   -  person Clinton Pierce    schedule 15.09.2011
comment
Попытка помочь другим, которые не знают лучше, чем скопировать / вставить код, который они видят здесь.   -  person John Saunders    schedule 15.09.2011


Ответы (3)


Я не думаю, что есть встроенный способ сделать это. Я думаю, что вы должны прочитать Атрибуты и довольствоваться собой.

e.g.

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 . . .
person Conrad Frix    schedule 15.09.2011

Вы можете попробовать метод XmlNode.CloneNode (bool deep).

deep: true, чтобы рекурсивно клонировать поддерево под указанным узлом; false, чтобы клонировать только сам узел.

person slobodans    schedule 15.09.2011
comment
У него нет XmlNode для клонирования, потому что потомки слишком громоздки. - person Kyle W; 15.09.2011

Не обязательно хороший способ, но вы можете прочитать строку, пока не дойдете до конца начального тега, а затем вручную добавить конечный тег и загрузить его в XmlDocument.

редактировать:

Думая что-то вроде:

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

Это может быть вообще недопустимо, учитывая, что здесь есть большая строка. Ваш способ может быть лучшим. Ни то, ни другое не красиво, но лично я не могу придумать лучшего способа, учитывая ваши ограничения (что не означает, что лучшего способа не существует).

person Kyle W    schedule 15.09.2011
comment
Я подумал о чем-то вроде: if (r.HasAttributes) for (int i = 0; i < r.AttributeCount; i++) { r.MoveToAttribute(i); atts[r.Name] = r.Value; // Dictionary<string, string> } А затем перестройте XML для узла, как вы предлагаете, но это показалось... уродливым. - person Clinton Pierce; 15.09.2011