Add support for elements preceding the document node in wxXML.
This is mainly useful for parsing and generating processing instructions but can be used for any kind of elements, e.g. also comments, occurring before the document node in XML documents. Closes #11593. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67346 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -454,6 +454,7 @@ All:
|
|||||||
- Added precision parameter to wxString::From[C]Double().
|
- Added precision parameter to wxString::From[C]Double().
|
||||||
- Added wxThread::Wait() and Delete() "wait mode" parameter (Catalin Raceanu).
|
- Added wxThread::Wait() and Delete() "wait mode" parameter (Catalin Raceanu).
|
||||||
- Allow showing milliseconds in wxLog time stamps (tan).
|
- Allow showing milliseconds in wxLog time stamps (tan).
|
||||||
|
- Added support for processing instructions in wxXmlDocument (Nick Matthews).
|
||||||
|
|
||||||
Unix:
|
Unix:
|
||||||
|
|
||||||
|
@@ -257,7 +257,7 @@ public:
|
|||||||
const wxString& encoding = wxT("UTF-8"));
|
const wxString& encoding = wxT("UTF-8"));
|
||||||
wxXmlDocument(wxInputStream& stream,
|
wxXmlDocument(wxInputStream& stream,
|
||||||
const wxString& encoding = wxT("UTF-8"));
|
const wxString& encoding = wxT("UTF-8"));
|
||||||
virtual ~wxXmlDocument() { wxDELETE(m_root); }
|
virtual ~wxXmlDocument() { wxDELETE(m_docNode); }
|
||||||
|
|
||||||
wxXmlDocument(const wxXmlDocument& doc);
|
wxXmlDocument(const wxXmlDocument& doc);
|
||||||
wxXmlDocument& operator=(const wxXmlDocument& doc);
|
wxXmlDocument& operator=(const wxXmlDocument& doc);
|
||||||
@@ -273,10 +273,13 @@ public:
|
|||||||
virtual bool Save(const wxString& filename, int indentstep = 2) const;
|
virtual bool Save(const wxString& filename, int indentstep = 2) const;
|
||||||
virtual bool Save(wxOutputStream& stream, int indentstep = 2) const;
|
virtual bool Save(wxOutputStream& stream, int indentstep = 2) const;
|
||||||
|
|
||||||
bool IsOk() const { return m_root != NULL; }
|
bool IsOk() const { return GetRoot() != NULL; }
|
||||||
|
|
||||||
// Returns root node of the document.
|
// Returns root node of the document.
|
||||||
wxXmlNode *GetRoot() const { return m_root; }
|
wxXmlNode *GetRoot() const;
|
||||||
|
// Returns the document node.
|
||||||
|
wxXmlNode *GetDocumentNode() const { return m_docNode; }
|
||||||
|
|
||||||
|
|
||||||
// Returns version of document (may be empty).
|
// Returns version of document (may be empty).
|
||||||
const wxString& GetVersion() const { return m_version; }
|
const wxString& GetVersion() const { return m_version; }
|
||||||
@@ -286,10 +289,13 @@ public:
|
|||||||
const wxString& GetFileEncoding() const { return m_fileEncoding; }
|
const wxString& GetFileEncoding() const { return m_fileEncoding; }
|
||||||
|
|
||||||
// Write-access methods:
|
// Write-access methods:
|
||||||
wxXmlNode *DetachRoot() { wxXmlNode *old=m_root; m_root=NULL; return old; }
|
wxXmlNode *DetachDocumentNode() { wxXmlNode *old=m_docNode; m_docNode=NULL; return old; }
|
||||||
void SetRoot(wxXmlNode *node) { wxDELETE(m_root); m_root = node; }
|
void SetDocumentNode(wxXmlNode *node) { wxDELETE(m_docNode); m_docNode = node; }
|
||||||
|
wxXmlNode *DetachRoot();
|
||||||
|
void SetRoot(wxXmlNode *node);
|
||||||
void SetVersion(const wxString& version) { m_version = version; }
|
void SetVersion(const wxString& version) { m_version = version; }
|
||||||
void SetFileEncoding(const wxString& encoding) { m_fileEncoding = encoding; }
|
void SetFileEncoding(const wxString& encoding) { m_fileEncoding = encoding; }
|
||||||
|
void AppendToProlog(wxXmlNode *node);
|
||||||
|
|
||||||
#if !wxUSE_UNICODE
|
#if !wxUSE_UNICODE
|
||||||
// Returns encoding of in-memory representation of the document
|
// Returns encoding of in-memory representation of the document
|
||||||
@@ -307,7 +313,7 @@ private:
|
|||||||
#if !wxUSE_UNICODE
|
#if !wxUSE_UNICODE
|
||||||
wxString m_encoding;
|
wxString m_encoding;
|
||||||
#endif
|
#endif
|
||||||
wxXmlNode *m_root;
|
wxXmlNode *m_docNode;
|
||||||
|
|
||||||
void DoCopy(const wxXmlDocument& doc);
|
void DoCopy(const wxXmlDocument& doc);
|
||||||
|
|
||||||
|
@@ -40,6 +40,11 @@ enum wxXmlNodeType
|
|||||||
@c title and irrelevant content and one child of type @c wxXML_TEXT_NODE
|
@c title and irrelevant content and one child of type @c wxXML_TEXT_NODE
|
||||||
with @c hi as content.
|
with @c hi as content.
|
||||||
|
|
||||||
|
The @c wxXML_PI_NODE type sets the name to the PI target and the contents to
|
||||||
|
the instructions. Note that whilst the PI instructions are often in the form
|
||||||
|
of pseudo-attributes these do not use the nodes attribute system. It is the users
|
||||||
|
responsibility to code and decode the instruction text.
|
||||||
|
|
||||||
If @c wxUSE_UNICODE is 0, all strings are encoded in the encoding given to
|
If @c wxUSE_UNICODE is 0, all strings are encoded in the encoding given to
|
||||||
wxXmlDocument::Load (default is UTF-8).
|
wxXmlDocument::Load (default is UTF-8).
|
||||||
|
|
||||||
@@ -179,7 +184,7 @@ public:
|
|||||||
|
|
||||||
This function searches only the parents of this node until it finds
|
This function searches only the parents of this node until it finds
|
||||||
@a grandparent or the @NULL node (which is the parent of non-linked
|
@a grandparent or the @NULL node (which is the parent of non-linked
|
||||||
nodes or the parent of a wxXmlDocument's root node).
|
nodes or the parent of a wxXmlDocument's root element node).
|
||||||
*/
|
*/
|
||||||
int GetDepth(wxXmlNode* grandparent = NULL) const;
|
int GetDepth(wxXmlNode* grandparent = NULL) const;
|
||||||
|
|
||||||
@@ -215,14 +220,14 @@ public:
|
|||||||
is represented by expat with the following tag tree:
|
is represented by expat with the following tag tree:
|
||||||
|
|
||||||
@code
|
@code
|
||||||
wxXML_ENTITY_NODE name="tagname", content=""
|
wxXML_ELEMENT_NODE name="tagname", content=""
|
||||||
|-- wxXML_TEXT_NODE name="", content="tagcontent"
|
|-- wxXML_TEXT_NODE name="", content="tagcontent"
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
or eventually:
|
or eventually:
|
||||||
|
|
||||||
@code
|
@code
|
||||||
wxXML_ENTITY_NODE name="tagname", content=""
|
wxXML_ELEMENT_NODE name="tagname", content=""
|
||||||
|-- wxXML_CDATA_SECTION_NODE name="", content="tagcontent"
|
|-- wxXML_CDATA_SECTION_NODE name="", content="tagcontent"
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
@@ -449,6 +454,20 @@ public:
|
|||||||
if (doc.GetRoot()->GetName() != "myroot-node")
|
if (doc.GetRoot()->GetName() != "myroot-node")
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// examine prologue
|
||||||
|
wxXmlNode *prolog = doc.GetDocumentNode()->GetChildren();
|
||||||
|
while (prolog) {
|
||||||
|
|
||||||
|
if (prolog->GetType() == wxXML_PI_NODE && prolog->GetName() == "target") {
|
||||||
|
|
||||||
|
// process Process Instruction contents
|
||||||
|
wxString pi = prolog->GetContent();
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wxXmlNode *child = doc.GetRoot()->GetChildren();
|
wxXmlNode *child = doc.GetRoot()->GetChildren();
|
||||||
while (child) {
|
while (child) {
|
||||||
|
|
||||||
@@ -533,13 +552,37 @@ public:
|
|||||||
virtual ~wxXmlDocument();
|
virtual ~wxXmlDocument();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Detaches the document root node and returns it.
|
Appends a Process Instruction or Comment node to the document prologue.
|
||||||
|
|
||||||
The document root node will be set to @NULL and thus IsOk() will
|
Calling this function will create a prologue or attach the node to the
|
||||||
|
end of an existing prologue.
|
||||||
|
|
||||||
|
@since 2.9.2
|
||||||
|
*/
|
||||||
|
void AppendToProlog(wxXmlNode* node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Detaches the document node and returns it.
|
||||||
|
|
||||||
|
The document node will be set to @NULL and thus IsOk() will
|
||||||
return @false after calling this function.
|
return @false after calling this function.
|
||||||
|
|
||||||
Note that the caller is responsible for deleting the returned node in order
|
Note that the caller is responsible for deleting the returned node in order
|
||||||
to avoid memory leaks.
|
to avoid memory leaks.
|
||||||
|
|
||||||
|
@since 2.9.2
|
||||||
|
*/
|
||||||
|
wxXmlNode* DetachDocumentNode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Detaches the root entity node and returns it.
|
||||||
|
|
||||||
|
After calling this function, the document node will remain together with
|
||||||
|
any prologue nodes, but IsOk() will return @false since the root entity
|
||||||
|
will be missing.
|
||||||
|
|
||||||
|
Note that the caller is reponsible for deleting the returned node in order
|
||||||
|
to avoid memory leaks.
|
||||||
*/
|
*/
|
||||||
wxXmlNode* DetachRoot();
|
wxXmlNode* DetachRoot();
|
||||||
|
|
||||||
@@ -560,7 +603,14 @@ public:
|
|||||||
const wxString& GetFileEncoding() const;
|
const wxString& GetFileEncoding() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the root node of the document.
|
Returns the document node of the document.
|
||||||
|
|
||||||
|
@since 2.9.2
|
||||||
|
*/
|
||||||
|
wxXmlNode* GetDocumentNode() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the root element node of the document.
|
||||||
*/
|
*/
|
||||||
wxXmlNode* GetRoot() const;
|
wxXmlNode* GetRoot() const;
|
||||||
|
|
||||||
@@ -620,7 +670,18 @@ public:
|
|||||||
virtual bool Save(wxOutputStream& stream, int indentstep = 2) const;
|
virtual bool Save(wxOutputStream& stream, int indentstep = 2) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the enconding of the document.
|
Sets the document node of this document.
|
||||||
|
|
||||||
|
Deletes any previous document node.
|
||||||
|
Use DetachDocumentNode() and then SetDocumentNode() if you want to
|
||||||
|
replace the document node without deleting the old document tree.
|
||||||
|
|
||||||
|
@since 2.9.2
|
||||||
|
*/
|
||||||
|
void SetDocumentNode(wxXmlNode* node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the encoding of the document.
|
||||||
*/
|
*/
|
||||||
void SetEncoding(const wxString& enc);
|
void SetEncoding(const wxString& enc);
|
||||||
|
|
||||||
@@ -630,9 +691,10 @@ public:
|
|||||||
void SetFileEncoding(const wxString& encoding);
|
void SetFileEncoding(const wxString& encoding);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the root node of this document. Deletes previous root node.
|
Sets the root element node of this document.
|
||||||
Use DetachRoot() and then SetRoot() if you want to replace the root
|
|
||||||
node without deleting the old document tree.
|
Will create the document node if necessary. Any previous
|
||||||
|
root element node is deleted.
|
||||||
*/
|
*/
|
||||||
void SetRoot(wxXmlNode* node);
|
void SetRoot(wxXmlNode* node);
|
||||||
|
|
||||||
|
186
src/xml/xml.cpp
186
src/xml/xml.cpp
@@ -396,7 +396,7 @@ bool wxXmlNode::IsWhitespaceOnly() const
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
wxXmlDocument::wxXmlDocument()
|
wxXmlDocument::wxXmlDocument()
|
||||||
: m_version(wxS("1.0")), m_fileEncoding(wxS("utf-8")), m_root(NULL)
|
: m_version(wxS("1.0")), m_fileEncoding(wxS("UTF-8")), m_docNode(NULL)
|
||||||
{
|
{
|
||||||
#if !wxUSE_UNICODE
|
#if !wxUSE_UNICODE
|
||||||
m_encoding = wxS("UTF-8");
|
m_encoding = wxS("UTF-8");
|
||||||
@@ -404,20 +404,20 @@ wxXmlDocument::wxXmlDocument()
|
|||||||
}
|
}
|
||||||
|
|
||||||
wxXmlDocument::wxXmlDocument(const wxString& filename, const wxString& encoding)
|
wxXmlDocument::wxXmlDocument(const wxString& filename, const wxString& encoding)
|
||||||
:wxObject(), m_root(NULL)
|
:wxObject(), m_docNode(NULL)
|
||||||
{
|
{
|
||||||
if ( !Load(filename, encoding) )
|
if ( !Load(filename, encoding) )
|
||||||
{
|
{
|
||||||
wxDELETE(m_root);
|
wxDELETE(m_docNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wxXmlDocument::wxXmlDocument(wxInputStream& stream, const wxString& encoding)
|
wxXmlDocument::wxXmlDocument(wxInputStream& stream, const wxString& encoding)
|
||||||
:wxObject(), m_root(NULL)
|
:wxObject(), m_docNode(NULL)
|
||||||
{
|
{
|
||||||
if ( !Load(stream, encoding) )
|
if ( !Load(stream, encoding) )
|
||||||
{
|
{
|
||||||
wxDELETE(m_root);
|
wxDELETE(m_docNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +429,7 @@ wxXmlDocument::wxXmlDocument(const wxXmlDocument& doc)
|
|||||||
|
|
||||||
wxXmlDocument& wxXmlDocument::operator=(const wxXmlDocument& doc)
|
wxXmlDocument& wxXmlDocument::operator=(const wxXmlDocument& doc)
|
||||||
{
|
{
|
||||||
wxDELETE(m_root);
|
wxDELETE(m_docNode);
|
||||||
DoCopy(doc);
|
DoCopy(doc);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -442,10 +442,10 @@ void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
|
|||||||
#endif
|
#endif
|
||||||
m_fileEncoding = doc.m_fileEncoding;
|
m_fileEncoding = doc.m_fileEncoding;
|
||||||
|
|
||||||
if (doc.m_root)
|
if (doc.m_docNode)
|
||||||
m_root = new wxXmlNode(*doc.m_root);
|
m_docNode = new wxXmlNode(*doc.m_docNode);
|
||||||
else
|
else
|
||||||
m_root = NULL;
|
m_docNode = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxXmlDocument::Load(const wxString& filename, const wxString& encoding, int flags)
|
bool wxXmlDocument::Load(const wxString& filename, const wxString& encoding, int flags)
|
||||||
@@ -464,7 +464,83 @@ bool wxXmlDocument::Save(const wxString& filename, int indentstep) const
|
|||||||
return Save(stream, indentstep);
|
return Save(stream, indentstep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxXmlNode *wxXmlDocument::GetRoot() const
|
||||||
|
{
|
||||||
|
wxXmlNode *node = m_docNode;
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
node = m_docNode->GetChildren();
|
||||||
|
while (node != NULL && node->GetType() != wxXML_ELEMENT_NODE)
|
||||||
|
node = node->GetNext();
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxXmlNode *wxXmlDocument::DetachRoot()
|
||||||
|
{
|
||||||
|
wxXmlNode *node = m_docNode;
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
node = m_docNode->GetChildren();
|
||||||
|
wxXmlNode *prev = NULL;
|
||||||
|
while (node != NULL && node->GetType() != wxXML_ELEMENT_NODE)
|
||||||
|
{
|
||||||
|
prev = node;
|
||||||
|
node = node->GetNext();
|
||||||
|
}
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
if (node == m_docNode->GetChildren())
|
||||||
|
m_docNode->SetChildren(node->GetNext());
|
||||||
|
|
||||||
|
if (prev)
|
||||||
|
prev->SetNext(node->GetNext());
|
||||||
|
|
||||||
|
node->SetParent(NULL);
|
||||||
|
node->SetNext(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxXmlDocument::SetRoot(wxXmlNode *root)
|
||||||
|
{
|
||||||
|
wxXmlNode *node = m_docNode;
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
node = m_docNode->GetChildren();
|
||||||
|
wxXmlNode *prev = NULL;
|
||||||
|
while (node != NULL && node->GetType() != wxXML_ELEMENT_NODE)
|
||||||
|
{
|
||||||
|
prev = node;
|
||||||
|
node = node->GetNext();
|
||||||
|
}
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
root->SetNext( node->GetNext() );
|
||||||
|
wxDELETE(node);
|
||||||
|
}
|
||||||
|
if (prev)
|
||||||
|
prev->SetNext(root);
|
||||||
|
else
|
||||||
|
m_docNode->SetChildren(root);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_docNode = new wxXmlNode(wxXML_DOCUMENT_NODE, wxEmptyString);
|
||||||
|
}
|
||||||
|
root->SetParent(m_docNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxXmlDocument::AppendToProlog(wxXmlNode *node)
|
||||||
|
{
|
||||||
|
if (!m_docNode)
|
||||||
|
m_docNode = new wxXmlNode(wxXML_DOCUMENT_NODE, wxEmptyString);
|
||||||
|
if (IsOk())
|
||||||
|
m_docNode->InsertChild( node, GetRoot() );
|
||||||
|
else
|
||||||
|
m_docNode->AddChild( node );
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// wxXmlDocument loading routines
|
// wxXmlDocument loading routines
|
||||||
@@ -509,7 +585,6 @@ struct wxXmlParsingContext
|
|||||||
{
|
{
|
||||||
wxXmlParsingContext()
|
wxXmlParsingContext()
|
||||||
: conv(NULL),
|
: conv(NULL),
|
||||||
root(NULL),
|
|
||||||
node(NULL),
|
node(NULL),
|
||||||
lastChild(NULL),
|
lastChild(NULL),
|
||||||
lastAsText(NULL),
|
lastAsText(NULL),
|
||||||
@@ -518,7 +593,6 @@ struct wxXmlParsingContext
|
|||||||
|
|
||||||
XML_Parser parser;
|
XML_Parser parser;
|
||||||
wxMBConv *conv;
|
wxMBConv *conv;
|
||||||
wxXmlNode *root;
|
|
||||||
wxXmlNode *node; // the node being parsed
|
wxXmlNode *node; // the node being parsed
|
||||||
wxXmlNode *lastChild; // the last child of "node"
|
wxXmlNode *lastChild; // the last child of "node"
|
||||||
wxXmlNode *lastAsText; // the last _text_ child of "node"
|
wxXmlNode *lastAsText; // the last _text_ child of "node"
|
||||||
@@ -551,16 +625,8 @@ static void StartElementHnd(void *userData, const char *name, const char **atts)
|
|||||||
a += 2;
|
a += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->root == NULL)
|
ASSERT_LAST_CHILD_OK(ctx);
|
||||||
{
|
ctx->node->InsertChildAfter(node, ctx->lastChild);
|
||||||
ctx->root = node;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASSERT_LAST_CHILD_OK(ctx);
|
|
||||||
ctx->node->InsertChildAfter(node, ctx->lastChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->lastAsText = NULL;
|
ctx->lastAsText = NULL;
|
||||||
ctx->lastChild = NULL; // our new node "node" has no children yet
|
ctx->lastChild = NULL; // our new node "node" has no children yet
|
||||||
|
|
||||||
@@ -636,21 +702,29 @@ static void CommentHnd(void *userData, const char *data)
|
|||||||
{
|
{
|
||||||
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
||||||
|
|
||||||
if (ctx->node)
|
wxXmlNode *commentnode =
|
||||||
{
|
new wxXmlNode(wxXML_COMMENT_NODE,
|
||||||
wxXmlNode *commentnode =
|
wxS("comment"), CharToString(ctx->conv, data),
|
||||||
new wxXmlNode(wxXML_COMMENT_NODE,
|
XML_GetCurrentLineNumber(ctx->parser));
|
||||||
wxS("comment"), CharToString(ctx->conv, data),
|
|
||||||
XML_GetCurrentLineNumber(ctx->parser));
|
|
||||||
|
|
||||||
ASSERT_LAST_CHILD_OK(ctx);
|
ASSERT_LAST_CHILD_OK(ctx);
|
||||||
ctx->node->InsertChildAfter(commentnode, ctx->lastChild);
|
ctx->node->InsertChildAfter(commentnode, ctx->lastChild);
|
||||||
ctx->lastChild = commentnode;
|
ctx->lastChild = commentnode;
|
||||||
}
|
ctx->lastAsText = NULL;
|
||||||
//else: ctx->node == NULL happens if there is a comment before
|
}
|
||||||
// the root element. We current don't have a way to represent
|
|
||||||
// these in wxXmlDocument (FIXME).
|
|
||||||
|
|
||||||
|
static void PIHnd(void *userData, const char *target, const char *data)
|
||||||
|
{
|
||||||
|
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
||||||
|
|
||||||
|
wxXmlNode *pinode =
|
||||||
|
new wxXmlNode(wxXML_PI_NODE, CharToString(ctx->conv, target),
|
||||||
|
CharToString(ctx->conv, data),
|
||||||
|
XML_GetCurrentLineNumber(ctx->parser));
|
||||||
|
|
||||||
|
ASSERT_LAST_CHILD_OK(ctx);
|
||||||
|
ctx->node->InsertChildAfter(pinode, ctx->lastChild);
|
||||||
|
ctx->lastChild = pinode;
|
||||||
ctx->lastAsText = NULL;
|
ctx->lastAsText = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,6 +792,7 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int fl
|
|||||||
wxXmlParsingContext ctx;
|
wxXmlParsingContext ctx;
|
||||||
bool done;
|
bool done;
|
||||||
XML_Parser parser = XML_ParserCreate(NULL);
|
XML_Parser parser = XML_ParserCreate(NULL);
|
||||||
|
wxXmlNode *root = new wxXmlNode(wxXML_DOCUMENT_NODE, wxEmptyString);
|
||||||
|
|
||||||
ctx.encoding = wxS("UTF-8"); // default in absence of encoding=""
|
ctx.encoding = wxS("UTF-8"); // default in absence of encoding=""
|
||||||
ctx.conv = NULL;
|
ctx.conv = NULL;
|
||||||
@@ -727,12 +802,14 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int fl
|
|||||||
#endif
|
#endif
|
||||||
ctx.removeWhiteOnlyNodes = (flags & wxXMLDOC_KEEP_WHITESPACE_NODES) == 0;
|
ctx.removeWhiteOnlyNodes = (flags & wxXMLDOC_KEEP_WHITESPACE_NODES) == 0;
|
||||||
ctx.parser = parser;
|
ctx.parser = parser;
|
||||||
|
ctx.node = root;
|
||||||
|
|
||||||
XML_SetUserData(parser, (void*)&ctx);
|
XML_SetUserData(parser, (void*)&ctx);
|
||||||
XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
|
XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
|
||||||
XML_SetCharacterDataHandler(parser, TextHnd);
|
XML_SetCharacterDataHandler(parser, TextHnd);
|
||||||
XML_SetCdataSectionHandler(parser, StartCdataHnd, EndCdataHnd);;
|
XML_SetCdataSectionHandler(parser, StartCdataHnd, EndCdataHnd);;
|
||||||
XML_SetCommentHandler(parser, CommentHnd);
|
XML_SetCommentHandler(parser, CommentHnd);
|
||||||
|
XML_SetProcessingInstructionHandler(parser, PIHnd);
|
||||||
XML_SetDefaultHandler(parser, DefaultHnd);
|
XML_SetDefaultHandler(parser, DefaultHnd);
|
||||||
XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL);
|
XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL);
|
||||||
|
|
||||||
@@ -759,11 +836,11 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int fl
|
|||||||
SetVersion(ctx.version);
|
SetVersion(ctx.version);
|
||||||
if (!ctx.encoding.empty())
|
if (!ctx.encoding.empty())
|
||||||
SetFileEncoding(ctx.encoding);
|
SetFileEncoding(ctx.encoding);
|
||||||
SetRoot(ctx.root);
|
SetDocumentNode(root);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
delete ctx.root;
|
delete root;
|
||||||
}
|
}
|
||||||
|
|
||||||
XML_ParserFree(parser);
|
XML_ParserFree(parser);
|
||||||
@@ -995,6 +1072,14 @@ bool OutputNode(wxOutputStream& stream,
|
|||||||
OutputString(stream, wxS("-->"), convMem, convFile);
|
OutputString(stream, wxS("-->"), convMem, convFile);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case wxXML_PI_NODE:
|
||||||
|
rc = OutputString(stream, wxT("<?"), convMem, convFile) &&
|
||||||
|
OutputString(stream, node->GetName(), convMem, convFile) &&
|
||||||
|
OutputString(stream, wxT(" "), convMem, convFile) &&
|
||||||
|
OutputString(stream, node->GetContent(), convMem, convFile) &&
|
||||||
|
OutputString(stream, wxT("?>"), convMem, convFile);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
wxFAIL_MSG("unsupported node type");
|
wxFAIL_MSG("unsupported node type");
|
||||||
rc = false;
|
rc = false;
|
||||||
@@ -1023,17 +1108,24 @@ bool wxXmlDocument::Save(wxOutputStream& stream, int indentstep) const
|
|||||||
//else: file and in-memory encodings are the same, no conversion needed
|
//else: file and in-memory encodings are the same, no conversion needed
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return OutputString(stream,
|
wxString dec = wxString::Format(
|
||||||
wxString::Format
|
wxS("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
|
||||||
(
|
GetVersion(), GetFileEncoding()
|
||||||
wxS("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
|
);
|
||||||
GetVersion(), GetFileEncoding()
|
bool rc = OutputString(stream, dec, convMem.get(), convFile.get());
|
||||||
),
|
|
||||||
convMem.get(),
|
wxXmlNode *node = GetDocumentNode();
|
||||||
convFile.get()) &&
|
if ( node )
|
||||||
OutputNode(stream, GetRoot(), 0,
|
node = node->GetChildren();
|
||||||
convMem.get(), convFile.get(), indentstep) &&
|
|
||||||
OutputString(stream, wxS("\n"), convMem.get(), convFile.get());
|
while( rc && node )
|
||||||
|
{
|
||||||
|
rc = OutputNode(stream, node, 0, convMem.get(),
|
||||||
|
convFile.get(), indentstep) &&
|
||||||
|
OutputString(stream, wxS("\n"), convMem.get(), convFile.get());
|
||||||
|
node = node->GetNext();
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ wxVersionInfo wxXmlDocument::GetLibraryVersionInfo()
|
/*static*/ wxVersionInfo wxXmlDocument::GetLibraryVersionInfo()
|
||||||
|
@@ -77,14 +77,20 @@ private:
|
|||||||
CPPUNIT_TEST( InsertChildAfter );
|
CPPUNIT_TEST( InsertChildAfter );
|
||||||
CPPUNIT_TEST( LoadSave );
|
CPPUNIT_TEST( LoadSave );
|
||||||
CPPUNIT_TEST( CDATA );
|
CPPUNIT_TEST( CDATA );
|
||||||
|
CPPUNIT_TEST( PI );
|
||||||
CPPUNIT_TEST( Escaping );
|
CPPUNIT_TEST( Escaping );
|
||||||
|
CPPUNIT_TEST( DetachRoot );
|
||||||
|
CPPUNIT_TEST( AppendToProlog );
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
void InsertChild();
|
void InsertChild();
|
||||||
void InsertChildAfter();
|
void InsertChildAfter();
|
||||||
void LoadSave();
|
void LoadSave();
|
||||||
void CDATA();
|
void CDATA();
|
||||||
|
void PI();
|
||||||
void Escaping();
|
void Escaping();
|
||||||
|
void DetachRoot();
|
||||||
|
void AppendToProlog();
|
||||||
|
|
||||||
DECLARE_NO_COPY_CLASS(XmlTestCase)
|
DECLARE_NO_COPY_CLASS(XmlTestCase)
|
||||||
};
|
};
|
||||||
@@ -150,6 +156,7 @@ void XmlTestCase::LoadSave()
|
|||||||
const char *xmlText =
|
const char *xmlText =
|
||||||
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
|
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
|
||||||
"<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
|
"<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
|
||||||
|
" <!-- Test comment -->\n"
|
||||||
" <object class=\"wxDialog\" name=\"my_dialog\">\n"
|
" <object class=\"wxDialog\" name=\"my_dialog\">\n"
|
||||||
" <children>\n"
|
" <children>\n"
|
||||||
" <grandchild id=\"1\"/>\n"
|
" <grandchild id=\"1\"/>\n"
|
||||||
@@ -194,6 +201,30 @@ void XmlTestCase::LoadSave()
|
|||||||
CPPUNIT_ASSERT_EQUAL( wxString(utf8xmlText),
|
CPPUNIT_ASSERT_EQUAL( wxString(utf8xmlText),
|
||||||
wxString(sos8.GetString().ToUTF8()) );
|
wxString(sos8.GetString().ToUTF8()) );
|
||||||
#endif // wxUSE_UNICODE
|
#endif // wxUSE_UNICODE
|
||||||
|
|
||||||
|
const char *xmlTextProlog =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
"<!-- Prolog comment -->\n"
|
||||||
|
"<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
|
||||||
|
"<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
|
||||||
|
" <!-- Test comment -->\n"
|
||||||
|
" <object class=\"wxDialog\" name=\"my_dialog\">\n"
|
||||||
|
" <children>\n"
|
||||||
|
" <grandchild id=\"1\"/>\n"
|
||||||
|
" </children>\n"
|
||||||
|
" <subobject/>\n"
|
||||||
|
" </object>\n"
|
||||||
|
"</resource>\n"
|
||||||
|
"<!-- Trailing comment -->\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
wxStringInputStream sisp(xmlTextProlog);
|
||||||
|
CPPUNIT_ASSERT( doc.Load(sisp, "UTF-8") );
|
||||||
|
|
||||||
|
wxStringOutputStream sosp;
|
||||||
|
CPPUNIT_ASSERT( doc.Save(sosp) );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL( xmlTextProlog, sosp.GetString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void XmlTestCase::CDATA()
|
void XmlTestCase::CDATA()
|
||||||
@@ -221,6 +252,28 @@ void XmlTestCase::CDATA()
|
|||||||
CPPUNIT_ASSERT_EQUAL( "Giovanni Mittone", n->GetContent() );
|
CPPUNIT_ASSERT_EQUAL( "Giovanni Mittone", n->GetContent() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XmlTestCase::PI()
|
||||||
|
{
|
||||||
|
const char *xmlText =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
|
||||||
|
"<root>\n"
|
||||||
|
" <?robot index=\"no\" follow=\"no\"?>\n"
|
||||||
|
"</root>\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
wxStringInputStream sis(xmlText);
|
||||||
|
wxXmlDocument doc;
|
||||||
|
CPPUNIT_ASSERT( doc.Load(sis) );
|
||||||
|
|
||||||
|
wxXmlNode *n = doc.GetRoot();
|
||||||
|
CPPUNIT_ASSERT( n );
|
||||||
|
|
||||||
|
n = n->GetChildren();
|
||||||
|
CPPUNIT_ASSERT( n );
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL( "index=\"no\" follow=\"no\"", n->GetContent() );
|
||||||
|
}
|
||||||
|
|
||||||
void XmlTestCase::Escaping()
|
void XmlTestCase::Escaping()
|
||||||
{
|
{
|
||||||
// Verify that attribute values are escaped correctly, see
|
// Verify that attribute values are escaped correctly, see
|
||||||
@@ -243,3 +296,131 @@ void XmlTestCase::Escaping()
|
|||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL( xmlText, sos.GetString() );
|
CPPUNIT_ASSERT_EQUAL( xmlText, sos.GetString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XmlTestCase::DetachRoot()
|
||||||
|
{
|
||||||
|
const char *xmlTextProlog =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
"<!-- Prolog comment -->\n"
|
||||||
|
"<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
|
||||||
|
"<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
|
||||||
|
" <!-- Test comment -->\n"
|
||||||
|
" <object class=\"wxDialog\" name=\"my_dialog\">\n"
|
||||||
|
" <children>\n"
|
||||||
|
" <grandchild id=\"1\"/>\n"
|
||||||
|
" </children>\n"
|
||||||
|
" <subobject/>\n"
|
||||||
|
" </object>\n"
|
||||||
|
"</resource>\n"
|
||||||
|
"<!-- Trailing comment -->\n"
|
||||||
|
;
|
||||||
|
const char *xmlTextHtm =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
|
||||||
|
"<html>\n"
|
||||||
|
" <head>\n"
|
||||||
|
" <title>Testing wxXml</title>\n"
|
||||||
|
" </head>\n"
|
||||||
|
" <body>\n"
|
||||||
|
" <p>Some body text</p>\n"
|
||||||
|
" </body>\n"
|
||||||
|
"</html>\n"
|
||||||
|
;
|
||||||
|
wxXmlDocument doc;
|
||||||
|
|
||||||
|
wxStringInputStream sish(xmlTextHtm);
|
||||||
|
CPPUNIT_ASSERT( doc.Load(sish) );
|
||||||
|
|
||||||
|
wxXmlNode *root = doc.DetachRoot();
|
||||||
|
|
||||||
|
wxStringInputStream sisp(xmlTextProlog);
|
||||||
|
CPPUNIT_ASSERT( doc.Load(sisp) );
|
||||||
|
|
||||||
|
doc.SetRoot(root);
|
||||||
|
|
||||||
|
wxStringOutputStream sos;
|
||||||
|
CPPUNIT_ASSERT( doc.Save(sos) );
|
||||||
|
|
||||||
|
const char *xmlTextResult1 =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
"<!-- Prolog comment -->\n"
|
||||||
|
"<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
|
||||||
|
"<html>\n"
|
||||||
|
" <head>\n"
|
||||||
|
" <title>Testing wxXml</title>\n"
|
||||||
|
" </head>\n"
|
||||||
|
" <body>\n"
|
||||||
|
" <p>Some body text</p>\n"
|
||||||
|
" </body>\n"
|
||||||
|
"</html>\n"
|
||||||
|
"<!-- Trailing comment -->\n"
|
||||||
|
;
|
||||||
|
CPPUNIT_ASSERT_EQUAL( xmlTextResult1, sos.GetString() );
|
||||||
|
|
||||||
|
wxStringInputStream sisp2(xmlTextProlog);
|
||||||
|
CPPUNIT_ASSERT( doc.Load(sisp2) );
|
||||||
|
|
||||||
|
root = doc.DetachRoot();
|
||||||
|
|
||||||
|
wxStringInputStream sish2(xmlTextHtm);
|
||||||
|
CPPUNIT_ASSERT( doc.Load(sish2) );
|
||||||
|
|
||||||
|
doc.SetRoot(root);
|
||||||
|
|
||||||
|
wxStringOutputStream sos2;
|
||||||
|
CPPUNIT_ASSERT( doc.Save(sos2) );
|
||||||
|
|
||||||
|
const char *xmlTextResult2 =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
|
||||||
|
"<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
|
||||||
|
" <!-- Test comment -->\n"
|
||||||
|
" <object class=\"wxDialog\" name=\"my_dialog\">\n"
|
||||||
|
" <children>\n"
|
||||||
|
" <grandchild id=\"1\"/>\n"
|
||||||
|
" </children>\n"
|
||||||
|
" <subobject/>\n"
|
||||||
|
" </object>\n"
|
||||||
|
"</resource>\n"
|
||||||
|
;
|
||||||
|
CPPUNIT_ASSERT_EQUAL( xmlTextResult2, sos2.GetString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void XmlTestCase::AppendToProlog()
|
||||||
|
{
|
||||||
|
const char *xmlText =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
"<root>\n"
|
||||||
|
" <p>Some text</p>\n"
|
||||||
|
"</root>\n"
|
||||||
|
;
|
||||||
|
wxXmlDocument rootdoc;
|
||||||
|
wxStringInputStream sis(xmlText);
|
||||||
|
CPPUNIT_ASSERT( rootdoc.Load(sis) );
|
||||||
|
wxXmlNode *root = rootdoc.DetachRoot();
|
||||||
|
|
||||||
|
wxXmlNode *comment1 = new wxXmlNode(wxXML_COMMENT_NODE, "comment",
|
||||||
|
" 1st prolog entry ");
|
||||||
|
wxXmlNode *pi = new wxXmlNode(wxXML_PI_NODE, "xml-stylesheet",
|
||||||
|
"href=\"style.css\" type=\"text/css\"");
|
||||||
|
wxXmlNode *comment2 = new wxXmlNode(wxXML_COMMENT_NODE, "comment",
|
||||||
|
" 3rd prolog entry ");
|
||||||
|
|
||||||
|
wxXmlDocument doc;
|
||||||
|
doc.AppendToProlog( comment1 );
|
||||||
|
doc.AppendToProlog( pi );
|
||||||
|
doc.SetRoot( root );
|
||||||
|
doc.AppendToProlog( comment2 );
|
||||||
|
|
||||||
|
wxStringOutputStream sos;
|
||||||
|
CPPUNIT_ASSERT( doc.Save(sos) );
|
||||||
|
|
||||||
|
const char *xmlTextResult =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
"<!-- 1st prolog entry -->\n"
|
||||||
|
"<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
|
||||||
|
"<!-- 3rd prolog entry -->\n"
|
||||||
|
"<root>\n"
|
||||||
|
" <p>Some text</p>\n"
|
||||||
|
"</root>\n"
|
||||||
|
;
|
||||||
|
CPPUNIT_ASSERT_EQUAL( xmlTextResult, sos.GetString() );
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user