Add support for DOCTYPE to wxXmlDocument.

Allow retrieving the DOCTYPE specified in an existing document as well as
specifying the DOCTYPE to use when writing a new one.

Closes #13779.
This commit is contained in:
Nick Matthews
2015-04-26 15:34:18 +02:00
committed by Vadim Zeitlin
parent 41b1ed9c2e
commit d13278ecc3
5 changed files with 336 additions and 2 deletions

View File

@@ -402,6 +402,56 @@ bool wxXmlNode::IsWhitespaceOnly() const
//-----------------------------------------------------------------------------
// wxXmlDoctype
//-----------------------------------------------------------------------------
void wxXmlDoctype::Clear()
{
m_rootName.clear();
m_systemId.clear();
m_publicId.clear();
}
wxString wxXmlDoctype::GetFullString() const
{
wxString content;
if ( !m_rootName.empty() )
{
content = m_rootName;
if ( !m_publicId.empty() )
{
content << wxS(" PUBLIC \"") << m_publicId << wxS("\"");
}
if ( !m_systemId.empty() )
{
if ( m_publicId.empty() )
content << wxS(" SYSTEM");
// Prefer to use double quotes, but switch to single ones if a
// double quote appears inside the string to be quoted.
wxString quote;
if ( m_systemId.find('\"') == wxString::npos )
quote = wxS('"');
else if ( m_systemId.find('\'') == wxString::npos )
quote = wxS('\'');
else // It's an error if we can't use either kind of quotes.
return wxString();
content << wxS(' ') << quote << m_systemId << quote;
}
}
return content;
}
bool wxXmlDoctype::IsValid() const
{
return !GetFullString().empty();
}
//-----------------------------------------------------------------------------
// wxXmlDocument
//-----------------------------------------------------------------------------
@@ -452,6 +502,7 @@ void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
m_encoding = doc.m_encoding;
#endif
m_fileEncoding = doc.m_fileEncoding;
m_doctype = doc.m_doctype;
if (doc.m_docNode)
m_docNode = new wxXmlNode(*doc.m_docNode);
@@ -607,6 +658,7 @@ struct wxXmlParsingContext
node(NULL),
lastChild(NULL),
lastAsText(NULL),
doctype(NULL),
removeWhiteOnlyNodes(false)
{}
@@ -617,6 +669,7 @@ struct wxXmlParsingContext
wxXmlNode *lastAsText; // the last _text_ child of "node"
wxString encoding;
wxString version;
wxXmlDoctype *doctype;
bool removeWhiteOnlyNodes;
};
@@ -747,6 +800,21 @@ static void PIHnd(void *userData, const char *target, const char *data)
ctx->lastAsText = NULL;
}
static void StartDoctypeHnd(void *userData, const char *doctypeName,
const char *sysid, const char *pubid,
int WXUNUSED(has_internal_subset))
{
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
*ctx->doctype = wxXmlDoctype(CharToString(ctx->conv, doctypeName),
CharToString(ctx->conv, sysid),
CharToString(ctx->conv, pubid));
}
static void EndDoctypeHnd(void *WXUNUSED(userData))
{
}
static void DefaultHnd(void *userData, const char *s, int len)
{
// XML header:
@@ -819,6 +887,7 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int fl
if ( encoding.CmpNoCase(wxS("UTF-8")) != 0 )
ctx.conv = new wxCSConv(encoding);
#endif
ctx.doctype = &m_doctype;
ctx.removeWhiteOnlyNodes = (flags & wxXMLDOC_KEEP_WHITESPACE_NODES) == 0;
ctx.parser = parser;
ctx.node = root;
@@ -829,6 +898,7 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int fl
XML_SetCdataSectionHandler(parser, StartCdataHnd, EndCdataHnd);
XML_SetCommentHandler(parser, CommentHnd);
XML_SetProcessingInstructionHandler(parser, PIHnd);
XML_SetDoctypeDeclHandler(parser, StartDoctypeHnd, EndDoctypeHnd);
XML_SetDefaultHandler(parser, DefaultHnd);
XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL);
@@ -1133,6 +1203,17 @@ bool wxXmlDocument::Save(wxOutputStream& stream, int indentstep) const
);
bool rc = OutputString(stream, dec, convMem.get(), convFile.get());
if ( rc )
{
const wxString doctype = m_doctype.GetFullString();
if ( !doctype.empty() )
{
rc = OutputString(stream,
wxS("<!DOCTYPE ") + doctype + wxS(">\n"),
convMem.get(), convFile.get());
}
}
wxXmlNode *node = GetDocumentNode();
if ( node )
node = node->GetChildren();