Самый быстрый способ добавить новый узел к концу xml?

Ваша ошибка в попытке декодировать один символ из ответа:

>>> snav_timetable[len(snav_timetable)-2]
'}'

Один символ не является документом JSON, поэтому по праву не удается выполнить синтаксический анализ. Вы хотите декодировать весь ответ :

snav_timetable_data = json.loads(snav_timetable)

Вы можете перейти к использованию библиотеки requests , вместо этого здесь происходит загрузка Ответы JSON из тривиального API:

import requests

snav_timetable_data = requests.get(snav_timetable_url).json()

snav_timetable_data_cleaned = []
for departure in snav_timetable_data['data']['ratesOutward']:
    snav_timetable_data_cleaned.append({
       'COMPANY': 'Snav',
       'CODICE CORSA': departure['coditinera'],
       'DEPARTURE DATE TIME': departure['strDatapart'],
       'ARRIVAL DATE TIME': departure['strDataarri']
    })

Обратите внимание, что мне пришлось исправить опечатку в эталоне времени прибытия; это strDataarri, а не strDatarri.

7
задан Ramesh Soni 11 May 2009 в 17:01
поделиться

9 ответов

Вам необходимо использовать метод включения XML.

Ваш error.xml (не изменяется, просто заглушка. Используется синтаксическими анализаторами XML для чтения) :

<?xml version="1.0"?>
<!DOCTYPE logfile [
<!ENTITY logrows    
 SYSTEM "errorrows.txt">
]>
<Errors>
&logrows;
</Errors>

Ваш файл errorrows.txt (изменяется, синтаксический анализатор xml его не понимает):

<Error>....</Error>
<Error>....</Error>
<Error>....</Error>

Затем, чтобы добавить запись в errorrows.txt:

using (StreamWriter sw = File.AppendText("logerrors.txt"))
{
    XmlTextWriter xtw = new XmlTextWriter(sw);

    xtw.WriteStartElement("Error");
    // ... write error messge here
    xtw.Close();
}

Или вы даже можете использовать .NET 3.5 XElement и добавьте текст в StreamWriter :

using (StreamWriter sw = File.AppendText("logerrors.txt"))
{
    XElement element = new XElement("Error");
    // ... write error messge here
    sw.WriteLine(element.ToString());
}

См. также статью Microsoft «Эффективные методы изменения больших файлов XML»

10
ответ дан 6 December 2019 в 08:17
поделиться

Во-первых, я бы дисквалифицировал System.Xml.XmlDocument, потому что это DOM , который требует синтаксического анализа и построения всего дерева в памяти, прежде чем его можно будет добавить. Это означает, что ваши 10 МБ текста будут более 10 МБ в памяти. Это означает, что он требует "большого объема памяти" и "времени".

Во-вторых, я бы дисквалифицировал System.Xml.XmlReader, потому что он требует сначала синтаксического анализа всего файла , прежде чем вы сможете понять, когда вы можете добавить к нему. Вам придется скопировать XmlReader в XmlWriter, поскольку вы не можете его изменить. Для этого необходимо продублировать ваш XML-код в памяти, прежде чем вы сможете его добавить.

Более быстрым решением для XmlDocument и XmlReader было бы манипулирование строкой (которое имеет свои собственные проблемы с памятью):

string xml = @"<Errors><error />...<error /></Errors>";
int idx = xml.LastIndexOf("</Errors>");

xml = xml.Substring(0, idx) + "<error>new error</error></Errors>";

Отрежьте конечный тег, добавьте новую ошибку и снова добавьте закрывающий тег.

Я полагаю, вы могли бы сходить с ума от этого и усечь свой файл на 9 символов и добавить к нему. Не нужно было бы читать файл и позволить ОС оптимизировать загрузку страницы (нужно было бы загружать только последний блок или что-то в этом роде).

System.IO.FileStream fs = System.IO.File.Open("log.xml", System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite);
fs.Seek(-("</Errors>".Length), System.IO.SeekOrigin.End);
fs.Write("<error>new error</error></Errors>");
fs.Close();

Это вызовет проблему, если ваш файл пуст или содержит только "<Ошибки > ", с которыми легко справиться, проверив длину.

7
ответ дан 6 December 2019 в 08:17
поделиться

Я бы использовал XmlDocument или XDocument для загрузки вашего файла, а затем обработал бы его соответствующим образом.

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

Зачем тебе скорость? У вас уже есть узкое место в производительности или вы ожидаете его?

1
ответ дан 6 December 2019 в 08:17
поделиться

Как ваш XML-файл представлен в коде? Вы пользуетесь System.XML-классами? В этом случае вы можете использовать XMLDocument.AppendChild.

0
ответ дан 6 December 2019 в 08:17
поделиться

Попробуйте это:

        var doc = new XmlDocument();
        doc.LoadXml("<Errors><error>This is my first error</error></Errors>");

        XmlNode root = doc.DocumentElement;

        //Create a new node.
        XmlElement elem = doc.CreateElement("error");
        elem.InnerText = "This is my error";

        //Add the node to the document.
        if (root != null) root.AppendChild(elem);

        doc.Save(Console.Out);
        Console.ReadLine();
1
ответ дан 6 December 2019 в 08:17
поделиться

Самым быстрым способом, вероятно, был бы прямой доступ к файлу.

using (StreamWriter file = File.AppendText("my.log"))
{
    file.BaseStream.Seek(-"</Errors>".Length, SeekOrigin.End);
    file.Write("   <Error>New error message.</Error></Errors>");
}

Но вы теряете все полезные функции XML и можете легко повредить файл.

3
ответ дан 6 December 2019 в 08:17
поделиться

Вот как это сделать в C, .NET должна быть похожей.

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

#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char** argv) {
        FILE *f;

        // Open the file
        f = fopen("log.xml", "r+");

        // Small buffer to determine length of \n (1 on Unix, 2 on PC)
        // You could always simply hard code this if you don't plan on 
        // porting to Unix.
        char nlbuf[10];
        sprintf(nlbuf, "\n");

        // How long is our end tag?
        long offset = strlen("</Errors>");

        // Add in an \n char.
        offset += strlen(nlbuf);

        // Seek to the END OF FILE, and then GO BACK the end tag and newline
        // so we use a NEGATIVE offset.
        fseek(f, offset * -1, SEEK_END);

        // Print out your new error line
        fprintf(f, "<Error>New error line</Error>\n");

        // Print out new ending tag.
        fprintf(f, "</Errors>\n");

        // Close and you're done
        fclose(f);
}
0
ответ дан 6 December 2019 в 08:17
поделиться

The quickest method is likely to be reading in the file using an XmlReader, and simply replicating each read node to a new stream using XmlWriter When you get to the point at which you encounter the closing tag, then you just need to output your additional element before coninuing the 'read and duplicate' cycle. This way is inevitably going to be harder than than reading the entire document into the DOM (XmlDocument class), but for large XML files, much quicker. Admittedly, using StreamReader/StreamWriter would be somewhat faster still, but pretty horrible to work with in code.

0
ответ дан 6 December 2019 в 08:17
поделиться

Используя строковые методы (например, поиск до конца файла с последующим перемещением назад) длина закрывающего тега) уязвима для неожиданных, но вполне законных изменений в структуре документа.

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

И вот ситуация, в которой использование строковых манипуляций полностью не обнаруживается:

<Error xmlns="not_your_namespace">
   ...
</Error>

Если вы используете XmlReader для обработки XML, хотя это может быть не так быстро, как поиск EOF, он также будет позволяют обрабатывать все эти возможные исключения.

0
ответ дан 6 December 2019 в 08:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: