Как создать файл XML с использованием классов и функций Qt и экранировать все символы, отличные от Unicode? - PullRequest
2 голосов
/ 02 мая 2019

Проблема

Я пытаюсь создать набор функций, который позволяет пользователю создавать XML и помещать его в XML-файл. Проблема в том, что пользователь может самостоятельно решить, какую кодировку XML и файла.
Итак, меня интересует ситуация, когда пользователь решил создать XML-код ASCII и поместить его в файл ASCII. Проблема в том, что он может захотеть поместить некоторые символы Unicode в XML-код ASCII, а я хотел бы, чтобы символ экранировал все символы, не входящие в ASCII.
Есть ли способ сделать это без реализации собственной функции конвертера?

Я пытался ...

Я уже пробовал QDomDocument класс и все, что с ним связано. Но он преобразует только недопустимые символы XML: <,>, & ...
И если я добавлю несколько символов Unicode, они не будут исключены, несмотря на кодировку, указанную в декларации XML.

Какой-то код

Один из примеров, как я пытаюсь это сделать

QString data("version=\"1.0\" encoding=ASCII");
QDomProcessingInstruction instr = m_doc.createProcessingInstruction("xml", data);
m_doc.appendChild(instr);
QDomElement elem = m_doc.createElement(elemName.getQString());
QDomNode appendTo = m_current.isNull() ? m_doc : m_current;
appendTo.appendChild(elem);
m_current = elem;
QDomText text = m_doc.createTextNode(elemValue.getQString());
m_current.appendChild(text);
m_current = m_current.parentNode();

Также пытались сделать это с помощью современного QXmlStreamWriter

QString output;
QXmlStreamWriter stream(&output);
stream.setCodec(QTextCodec::codecForName("Windows-1250"));
stream.writeStartDocument();
stream.writeStartElement("bookmark");
stream.writeTextElement("title", "&ö");
stream.writeEndElement(); // bookmark
stream.writeEndDocument();

Ожидаемый XML:

<?xml version="1.0" encoding="ASCII"?>
<Message>
  <Label>&#xF9; &lt;> &amp;' </Label>
  <Name>&amp;&#xF6;</Name>
  <Text>Hello</Text>
</Message>

Фактический XML:

<?xml version="1.0" encoding="ASCII"?>
<Message>
  <Label>ù &lt;> &amp;' </Label>
  <Name>&amp;ö</Name>
  <Text>Hello</Text>
</Message>

PS Я также попробовал более специфическую кодировку, такую ​​как Windows-1260, Windows-1268, но они не конвертировали их все, только ù преобразовал в &#xf9;, но ö остался ö. И даже в некоторой кодировке он вообще не конвертируется.

1 Ответ

1 голос
/ 03 мая 2019

Способ решить - использовать собственную функцию кодирования.

QString encodeEntities(QString sourceText)
{
    QString tempText(sourceText);
    int len = tempText.length();
    int i = 0;
    while( i<len )
    {
        if( tempText[i].unicode() > 128  ){
            QString replaceText = "&#x"+QString::number(tempText[i].unicode(),16)+";"; // HEX format
            tempText.replace(i,1,replaceText);
            len += replaceText.length()-1;
            i += replaceText.length();
        }else{
            QString replaceText = tempText[i];
            replaceText = replaceText.toHtmlEscaped(); // Warning! Read bottom note
            tempText.replace(i,1,replaceText);
            len += replaceText.length()-1;
            i += replaceText.length();
        }
    }
    return tempText;
}

А чтобы использовать QXmlStreamWriter, вам нужно сделать несколько хаков, см. Ниже:

    QString output;
    QXmlStreamWriter stream(&output);
    stream.setCodec(QTextCodec::codecForName("utf-8"));
    stream.writeStartDocument();
    stream.writeStartElement("bookmark");       //Start bookmark
    {
        stream.writeStartElement("title");      // Start title
        stream.writeCharacters("");             // You need this to create a closed element, if not will create an open element
        output.append(encodeEntities("&ö"));    // Hack to not use the codec from QXmlStreamWriter
        stream.writeEndElement();               // End title
    }
    stream.writeEndElement();                   // End bookmark
    stream.writeEndDocument();

Это работает для меня и выводит следующее:

<?xml version="1.0"?><bookmark><title>&amp;&#xf6;</title></bookmark>

ПРИМЕЧАНИЕ. toHtmlEscaped() преобразует текстовую строку в строку HTML с метасимволами HTML <,>, & и «заменяется сущностями HTML. [1]

[1] https://doc.qt.io/qt-5/qstring.html#toHtmlEscaped

...