diff --git a/SOURCES/0001-xmlparsing.patch b/SOURCES/0001-xmlparsing.patch
new file mode 100644
index 0000000..0cadff4
--- /dev/null
+++ b/SOURCES/0001-xmlparsing.patch
@@ -0,0 +1,1374 @@
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 16870b4..a1f5a65 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -20,6 +20,7 @@ SET(musicbrainz5_SOVERSION ${musicbrainz5_SOVERSION_MAJOR})
+
+ SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
+ FIND_PACKAGE(Neon REQUIRED)
++FIND_PACKAGE(LibXml2 REQUIRED)
+
+ SET(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)")
+ SET(EXEC_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE PATH "Installation prefix for executables and object code libraries" FORCE)
+diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
+index 3e11469..440d4f2 100644
+--- a/examples/CMakeLists.txt
++++ b/examples/CMakeLists.txt
+@@ -1,5 +1,5 @@
+-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include)
+-LINK_LIBRARIES(musicbrainz5 ${NEON_LIBRARIES})
++INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include ${LIBXML2_INCLUDE_DIR})
++LINK_LIBRARIES(musicbrainz5 ${NEON_LIBRARIES} ${LIBXML2_LIBRARIES})
+
+ ADD_EXECUTABLE(cdlookup cdlookup.cc)
+ ADD_EXECUTABLE(cdlookup_c cdlookup_c.c)
+diff --git a/include/musicbrainz5/xmlParser.h b/include/musicbrainz5/xmlParser.h
+index 56b29d7..45db5fc 100644
+--- a/include/musicbrainz5/xmlParser.h
++++ b/include/musicbrainz5/xmlParser.h
+@@ -1,733 +1,111 @@
+-/****************************************************************************/
+-/*! \mainpage XMLParser library
+- * \section intro_sec Introduction
+- *
+- * This is a basic XML parser written in ANSI C++ for portability.
+- * It works by using recursion and a node tree for breaking
+- * down the elements of an XML document.
+- *
+- * @version V2.43
+- * @author Frank Vanden Berghen
+- *
+- * Copyright (c) 2002, Business-Insight
+- * Business-Insight
+- * All rights reserved.
+- * See the file AFPL-license.txt about the licensing terms
+- *
+- * \section tutorial First Tutorial
+- * You can follow a simple Tutorial to know the basics...
+- *
+- * \section usage General usage: How to include the XMLParser library inside your project.
+- *
+- * The library is composed of two files: xmlParser.cpp and
+- * xmlParser.h. These are the ONLY 2 files that you need when
+- * using the library inside your own projects.
+- *
+- * All the functions of the library are documented inside the comments of the file
+- * xmlParser.h. These comments can be transformed in
+- * full-fledged HTML documentation using the DOXYGEN software: simply type: "doxygen doxy.cfg"
+- *
+- * By default, the XMLParser library uses (char*) for string representation.To use the (wchar_t*)
+- * version of the library, you need to define the "_UNICODE" preprocessor definition variable
+- * (this is usually done inside your project definition file) (This is done automatically for you
+- * when using Visual Studio).
+- *
+- * \section example Advanced Tutorial and Many Examples of usage.
+- *
+- * Some very small introductory examples are described inside the Tutorial file
+- * xmlParser.html
+- *
+- * Some additional small examples are also inside the file xmlTest.cpp
+- * (for the "char*" version of the library) and inside the file
+- * xmlTestUnicode.cpp (for the "wchar_t*"
+- * version of the library). If you have a question, please review these additionnal examples
+- * before sending an e-mail to the author.
+- *
+- * To build the examples:
+- * - linux/unix: type "make"
+- * - solaris: type "make -f makefile.solaris"
+- * - windows: Visual Studio: double-click on xmlParser.dsw
+- * (under Visual Studio .NET, the .dsp and .dsw files will be automatically converted to .vcproj and .sln files)
+- *
+- * In order to build the examples you need some additional files:
+- * - linux/unix: makefile
+- * - solaris: makefile.solaris
+- * - windows: Visual Studio: *.dsp, xmlParser.dsw and also xmlParser.lib and xmlParser.dll
+- *
+- * \section debugging Debugging with the XMLParser library
+- *
+- * \subsection debugwin Debugging under WINDOWS
+- *
+- * Inside Visual C++, the "debug versions" of the memory allocation functions are
+- * very slow: Do not forget to compile in "release mode" to get maximum speed.
+- * When I had to debug a software that was using the XMLParser Library, it was usually
+- * a nightmare because the library was sooOOOoooo slow in debug mode (because of the
+- * slow memory allocations in Debug mode). To solve this
+- * problem, during all the debugging session, I am now using a very fast DLL version of the
+- * XMLParser Library (the DLL is compiled in release mode). Using the DLL version of
+- * the XMLParser Library allows me to have lightening XML parsing speed even in debug!
+- * Other than that, the DLL version is useless: In the release version of my tool,
+- * I always use the normal, ".cpp"-based, XMLParser Library (I simply include the
+- * xmlParser.cpp and
+- * xmlParser.h files into the project).
+- *
+- * The file XMLNodeAutoexp.txt contains some
+- * "tweaks" that improve substancially the display of the content of the XMLNode objects
+- * inside the Visual Studio Debugger. Believe me, once you have seen inside the debugger
+- * the "smooth" display of the XMLNode objects, you cannot live without it anymore!
+- *
+- * \subsection debuglinux Debugging under LINUX/UNIX
+- *
+- * The speed of the debug version of the XMLParser library is tolerable so no extra
+- * work.has been done.
+- *
+- ****************************************************************************/
++/* --------------------------------------------------------------------------
+
+-#ifndef __INCLUDE_XML_NODE__
+-#define __INCLUDE_XML_NODE__
++ libmusicbrainz5 - Client library to access MusicBrainz
+
+-#include
++ Copyright (C) 2012 Christophe Fergeau
+
+-#ifdef _UNICODE
+-// If you comment the next "define" line then the library will never "switch to" _UNICODE (wchar_t*) mode (16/32 bits per characters).
+-// This is useful when you get error messages like:
+-// 'XMLNode::openFileHelper' : cannot convert parameter 2 from 'const char [5]' to 'const wchar_t *'
+-// The _XMLWIDECHAR preprocessor variable force the XMLParser library into either utf16/32-mode (the proprocessor variable
+-// must be defined) or utf8-mode(the pre-processor variable must be undefined).
+-#define _XMLWIDECHAR
+-#endif
+-
+-#if defined(WIN32) || defined(UNDER_CE) || defined(_WIN32) || defined(WIN64) || defined(__BORLANDC__)
+-// comment the next line if you are under windows and the compiler is not Microsoft Visual Studio (6.0 or .NET) or Borland
+-#define _XMLWINDOWS
+-#endif
+-
+-#ifdef XMLDLLENTRY
+-#undef XMLDLLENTRY
+-#endif
+-#ifdef _USE_XMLPARSER_DLL
+-#ifdef _DLL_EXPORTS_
+-#define XMLDLLENTRY __declspec(dllexport)
+-#else
+-#define XMLDLLENTRY __declspec(dllimport)
+-#endif
+-#else
+-#define XMLDLLENTRY
+-#endif
++ This file is part of libmusicbrainz5.
+
+-// uncomment the next line if you want no support for wchar_t* (no need for the or libraries anymore to compile)
+-//#define XML_NO_WIDE_CHAR
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of v2 of the GNU Lesser General Public
++ License as published by the Free Software Foundation.
+
+-#ifdef XML_NO_WIDE_CHAR
+-#undef _XMLWINDOWS
+-#undef _XMLWIDECHAR
+-#endif
++ libmusicbrainz5 is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
+
+-#ifdef _XMLWINDOWS
+-#include
+-#else
+-#define XMLDLLENTRY
+-#ifndef XML_NO_WIDE_CHAR
+-#include // to have 'wcsrtombs' for ANSI version
+- // to have 'mbsrtowcs' for WIDECHAR version
+-#endif
+-#endif
++ You should have received a copy of the GNU General Public License
++ along with this library. If not, see .
+
+-// Some common types for char set portable code
+-#ifdef _XMLWIDECHAR
+- #define _CXML(c) L ## c
+- #define XMLCSTR const wchar_t *
+- #define XMLSTR wchar_t *
+- #define XMLCHAR wchar_t
+-#else
+- #define _CXML(c) c
+- #define XMLCSTR const char *
+- #define XMLSTR char *
+- #define XMLCHAR char
+-#endif
+-#ifndef FALSE
+- #define FALSE 0
+-#endif /* FALSE */
+-#ifndef TRUE
+- #define TRUE 1
+-#endif /* TRUE */
++ $Id$
+
++----------------------------------------------------------------------------*/
++#ifndef _MUSICBRAINZ5_XMLPARSER_H
++#define _MUSICBRAINZ5_XMLPARSER_H
+
+-/// Enumeration for XML parse errors.
+-typedef enum XMLError
+-{
+- eXMLErrorNone = 0,
+- eXMLErrorMissingEndTag,
+- eXMLErrorNoXMLTagFound,
+- eXMLErrorEmpty,
+- eXMLErrorMissingTagName,
+- eXMLErrorMissingEndTagName,
+- eXMLErrorUnmatchedEndTag,
+- eXMLErrorUnmatchedEndClearTag,
+- eXMLErrorUnexpectedToken,
+- eXMLErrorNoElements,
+- eXMLErrorFileNotFound,
+- eXMLErrorFirstTagNotFound,
+- eXMLErrorUnknownCharacterEntity,
+- eXMLErrorCharacterCodeAbove255,
+- eXMLErrorCharConversionError,
+- eXMLErrorCannotOpenWriteFile,
+- eXMLErrorCannotWriteFile,
+-
+- eXMLErrorBase64DataSizeIsNotMultipleOf4,
+- eXMLErrorBase64DecodeIllegalCharacter,
+- eXMLErrorBase64DecodeTruncatedData,
+- eXMLErrorBase64DecodeBufferTooSmall
+-} XMLError;
++#include
++#include
+
++typedef xmlError XMLResults;
+
+-/// Enumeration used to manage type of data. Use in conjunction with structure XMLNodeContents
+-typedef enum XMLElementType
+-{
+- eNodeChild=0,
+- eNodeAttribute=1,
+- eNodeText=2,
+- eNodeClear=3,
+- eNodeNULL=4
+-} XMLElementType;
++const int eXMLErrorNone = 0;
+
+-/// Structure used to obtain error details if the parse fails.
+-typedef struct XMLResults
++class XMLAttribute;
++class XMLNode
+ {
+- enum XMLError error;
+- int nLine,nColumn;
+-} XMLResults;
+-
+-/// Structure for XML clear (unformatted) node (usually comments)
+-typedef struct XMLClear {
+- XMLCSTR lpszValue; XMLCSTR lpszOpenTag; XMLCSTR lpszCloseTag;
+-} XMLClear;
+-
+-/// Structure for XML attribute.
+-typedef struct XMLAttribute {
+- XMLCSTR lpszName; XMLCSTR lpszValue;
+-} XMLAttribute;
+-
+-/// XMLElementPosition are not interchangeable with simple indexes
+-typedef int XMLElementPosition;
+-
+-struct XMLNodeContents;
+-
+-/** @defgroup XMLParserGeneral The XML parser */
+-
+-/// Main Class representing a XML node
+-/**
+- * All operations are performed using this class.
+- * \note The constructors of the XMLNode class are protected, so use instead one of these four methods to get your first instance of XMLNode:
+- *
+- * - XMLNode::parseString
+- * - XMLNode::parseFile
+- * - XMLNode::openFileHelper
+- * - XMLNode::createXMLTopNode (or XMLNode::createXMLTopNode_WOSD)
+- *
*/
+-typedef struct XMLDLLENTRY XMLNode
+-{
+- private:
+-
+- struct XMLNodeDataTag;
+-
+- /// Constructors are protected, so use instead one of: XMLNode::parseString, XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
+- XMLNode(struct XMLNodeDataTag *pParent, XMLSTR lpszName, char isDeclaration);
+- /// Constructors are protected, so use instead one of: XMLNode::parseString, XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
+- XMLNode(struct XMLNodeDataTag *p);
+-
+- public:
+- static XMLCSTR getVersion();///< Return the XMLParser library version number
+-
+- /** @defgroup conversions Parsing XML files/strings to an XMLNode structure and Rendering XMLNode's to files/string.
+- * @ingroup XMLParserGeneral
+- * @{ */
+-
+- /// Parse an XML string and return the root of a XMLNode tree representing the string.
+- static XMLNode parseString (XMLCSTR lpXMLString, XMLCSTR tag=NULL, XMLResults *pResults=NULL);
+- /**< The "parseString" function parse an XML string and return the root of a XMLNode tree. The "opposite" of this function is
+- * the function "createXMLString" that re-creates an XML string from an XMLNode tree. If the XML document is corrupted, the
+- * "parseString" method will initialize the "pResults" variable with some information that can be used to trace the error.
+- * If you still want to parse the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the
+- * beginning of the "xmlParser.cpp" file.
+- *
+- * @param lpXMLString the XML string to parse
+- * @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term ( ... ?>).
+- * @param pResults a pointer to a XMLResults variable that will contain some information that can be used to trace the XML parsing error. You can have a user-friendly explanation of the parsing error with the "getError" function.
+- */
+-
+- /// Parse an XML file and return the root of a XMLNode tree representing the file.
+- static XMLNode parseFile (XMLCSTR filename, XMLCSTR tag=NULL, XMLResults *pResults=NULL);
+- /**< The "parseFile" function parse an XML file and return the root of a XMLNode tree. The "opposite" of this function is
+- * the function "writeToFile" that re-creates an XML file from an XMLNode tree. If the XML document is corrupted, the
+- * "parseFile" method will initialize the "pResults" variable with some information that can be used to trace the error.
+- * If you still want to parse the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the
+- * beginning of the "xmlParser.cpp" file.
+- *
+- * @param filename the path to the XML file to parse
+- * @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term ( ... ?>).
+- * @param pResults a pointer to a XMLResults variable that will contain some information that can be used to trace the XML parsing error. You can have a user-friendly explanation of the parsing error with the "getError" function.
+- */
++ public:
++ static XMLNode emptyNode();
++ bool isEmpty() const;
+
+- /// Parse an XML file and return the root of a XMLNode tree representing the file. A very crude error checking is made. An attempt to guess the Char Encoding used in the file is made.
+- static XMLNode openFileHelper(XMLCSTR filename, XMLCSTR tag=NULL);
+- /**< The "openFileHelper" function reports to the screen all the warnings and errors that occurred during parsing of the XML file.
+- * This function also tries to guess char Encoding (UTF-8, ASCII or SHIT-JIS) based on the first 200 bytes of the file. Since each
+- * application has its own way to report and deal with errors, you should rather use the "parseFile" function to parse XML files
+- * and program yourself thereafter an "error reporting" tailored for your needs (instead of using the very crude "error reporting"
+- * mechanism included inside the "openFileHelper" function).
+- *
+- * If the XML document is corrupted, the "openFileHelper" method will:
+- * - display an error message on the console (or inside a messageBox for windows).
+- * - stop execution (exit).
+- *
+- * I strongly suggest that you write your own "openFileHelper" method tailored to your needs. If you still want to parse
+- * the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the beginning of the "xmlParser.cpp" file.
+- *
+- * @param filename the path of the XML file to parse.
+- * @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term ( ... ?>).
+- */
++ virtual ~XMLNode() {};
+
+- static XMLCSTR getError(XMLError error); ///< this gives you a user-friendly explanation of the parsing error
++ const XMLAttribute getAttribute(const char *name = NULL) const;
++ bool isAttributeSet(const char *name) const;
+
+- /// Create an XML string starting from the current XMLNode.
+- XMLSTR createXMLString(int nFormat=1, int *pnSize=NULL) const;
+- /**< The returned string should be free'd using the "freeXMLString" function.
+- *
+- * If nFormat==0, no formatting is required otherwise this returns an user friendly XML string from a given element
+- * with appropriate white spaces and carriage returns. if pnSize is given it returns the size in character of the string. */
++ XMLNode getChildNode(const char *name = NULL) const;
++ XMLNode next() const;
++ const char *getName() const;
++ const char *getText() const;
+
+- /// Save the content of an xmlNode inside a file
+- XMLError writeToFile(XMLCSTR filename,
+- const char *encoding=NULL,
+- char nFormat=1) const;
+- /**< If nFormat==0, no formatting is required otherwise this returns an user friendly XML string from a given element with appropriate white spaces and carriage returns.
+- * If the global parameter "characterEncoding==encoding_UTF8", then the "encoding" parameter is ignored and always set to "utf-8".
+- * If the global parameter "characterEncoding==encoding_ShiftJIS", then the "encoding" parameter is ignored and always set to "SHIFT-JIS".
+- * If "_XMLWIDECHAR=1", then the "encoding" parameter is ignored and always set to "utf-16".
+- * If no "encoding" parameter is given the "ISO-8859-1" encoding is used. */
+- /** @} */
++ friend bool operator== (const XMLNode &lhs, const XMLNode &rhs);
+
+- /** @defgroup navigate Navigate the XMLNode structure
+- * @ingroup XMLParserGeneral
+- * @{ */
+- XMLCSTR getName() const; ///< name of the node
+- XMLCSTR getText(int i=0) const; ///< return ith text field
+- int nText() const; ///< nbr of text field
+- XMLNode getParentNode() const; ///< return the parent node
+- XMLNode getChildNode(int i=0) const; ///< return ith child node
+- XMLNode getChildNode(XMLCSTR name, int i) const; ///< return ith child node with specific name (return an empty node if failing). If i==-1, this returns the last XMLNode with the given name.
+- XMLNode getChildNode(XMLCSTR name, int *i=NULL) const; ///< return next child node with specific name (return an empty node if failing)
+- XMLNode getChildNodeWithAttribute(XMLCSTR tagName,
+- XMLCSTR attributeName,
+- XMLCSTR attributeValue=NULL,
+- int *i=NULL) const; ///< return child node with specific name/attribute (return an empty node if failing)
+- XMLNode getChildNodeByPath(XMLCSTR path, char createNodeIfMissing=0, XMLCHAR sep='/');
+- ///< return the first child node with specific path
+- XMLNode getChildNodeByPathNonConst(XMLSTR path, char createNodeIfMissing=0, XMLCHAR sep='/');
+- ///< return the first child node with specific path.
++ protected:
++ XMLNode(xmlNodePtr node): mNode(node) {};
+
+- int nChildNode(XMLCSTR name) const; ///< return the number of child node with specific name
+- int nChildNode() const; ///< nbr of child node
+- XMLAttribute getAttribute(int i=0) const; ///< return ith attribute
+- XMLCSTR getAttributeName(int i=0) const; ///< return ith attribute name
+- XMLCSTR getAttributeValue(int i=0) const; ///< return ith attribute value
+- char isAttributeSet(XMLCSTR name) const; ///< test if an attribute with a specific name is given
+- XMLCSTR getAttribute(XMLCSTR name, int i) const; ///< return ith attribute content with specific name (return a NULL if failing)
+- XMLCSTR getAttribute(XMLCSTR name, int *i=NULL) const; ///< return next attribute content with specific name (return a NULL if failing)
+- int nAttribute() const; ///< nbr of attribute
+- XMLClear getClear(int i=0) const; ///< return ith clear field (comments)
+- int nClear() const; ///< nbr of clear field
+- XMLNodeContents enumContents(XMLElementPosition i) const; ///< enumerate all the different contents (attribute,child,text, clear) of the current XMLNode. The order is reflecting the order of the original file/string. NOTE: 0 <= i < nElement();
+- int nElement() const; ///< nbr of different contents for current node
+- char isEmpty() const; ///< is this node Empty?
+- char isDeclaration() const; ///< is this node a declaration .... ?>
+- XMLNode deepCopy() const; ///< deep copy (duplicate/clone) a XMLNode
+- static XMLNode emptyNode(); ///< return XMLNode::emptyXMLNode;
+- /** @} */
++ xmlNodePtr mNode;
+
+- ~XMLNode();
+- XMLNode(const XMLNode &A); ///< to allow shallow/fast copy:
+- XMLNode& operator=( const XMLNode& A ); ///< to allow shallow/fast copy:
++ private:
++ xmlAttrPtr getAttributeRaw(const char *name) const;
++};
+
+- XMLNode(): d(NULL){};
+- static XMLNode emptyXMLNode;
+- static XMLClear emptyXMLClear;
+- static XMLAttribute emptyXMLAttribute;
+-
+- /** @defgroup xmlModify Create or Update the XMLNode structure
+- * @ingroup XMLParserGeneral
+- * The functions in this group allows you to create from scratch (or update) a XMLNode structure. Start by creating your top
+- * node with the "createXMLTopNode" function and then add new nodes with the "addChild" function. The parameter 'pos' gives
+- * the position where the childNode, the text or the XMLClearTag will be inserted. The default value (pos=-1) inserts at the
+- * end. The value (pos=0) insert at the beginning (Insertion at the beginning is slower than at the end).
+- *
+- * REMARK: 0 <= pos < nChild()+nText()+nClear()
+- */
+-
+- /** @defgroup creation Creating from scratch a XMLNode structure
+- * @ingroup xmlModify
+- * @{ */
+- static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE); ///< Create the top node of an XMLNode structure
+- XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1); ///< Add a new child node
+- XMLNode addChild(XMLNode nodeToAdd, XMLElementPosition pos=-1); ///< If the "nodeToAdd" has some parents, it will be detached from it's parents before being attached to the current XMLNode
+- XMLAttribute *addAttribute(XMLCSTR lpszName, XMLCSTR lpszValuev); ///< Add a new attribute
+- XMLCSTR addText(XMLCSTR lpszValue, XMLElementPosition pos=-1); ///< Add a new text content
+- XMLClear *addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, XMLElementPosition pos=-1);
+- /**< Add a new clear tag
+- * @param lpszOpen default value ""
+- */
+- /** @} */
+-
+- /** @defgroup xmlUpdate Updating Nodes
+- * @ingroup xmlModify
+- * Some update functions:
+- * @{
+- */
+- XMLCSTR updateName(XMLCSTR lpszName); ///< change node's name
+- XMLAttribute *updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); ///< if the attribute to update is missing, a new one will be added
+- XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName=NULL,int i=0); ///< if the attribute to update is missing, a new one will be added
+- XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName);///< set lpszNewName=NULL if you don't want to change the name of the attribute if the attribute to update is missing, a new one will be added
+- XMLCSTR updateText(XMLCSTR lpszNewValue, int i=0); ///< if the text to update is missing, a new one will be added
+- XMLCSTR updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one will be added
+- XMLClear *updateClear(XMLCSTR lpszNewContent, int i=0); ///< if the clearTag to update is missing, a new one will be added
+- XMLClear *updateClear(XMLClear *newP,XMLClear *oldP); ///< if the clearTag to update is missing, a new one will be added
+- XMLClear *updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new one will be added
+- /** @} */
+-
+- /** @defgroup xmlDelete Deleting Nodes or Attributes
+- * @ingroup xmlModify
+- * Some deletion functions:
+- * @{
+- */
+- /// The "deleteNodeContent" function forces the deletion of the content of this XMLNode and the subtree.
+- void deleteNodeContent();
+- /**< \note The XMLNode instances that are referring to the part of the subtree that has been deleted CANNOT be used anymore!!. Unexpected results will occur if you continue using them. */
+- void deleteAttribute(int i=0); ///< Delete the ith attribute of the current XMLNode
+- void deleteAttribute(XMLCSTR lpszName); ///< Delete the attribute with the given name (the "strcmp" function is used to find the right attribute)
+- void deleteAttribute(XMLAttribute *anAttribute); ///< Delete the attribute with the name "anAttribute->lpszName" (the "strcmp" function is used to find the right attribute)
+- void deleteText(int i=0); ///< Delete the Ith text content of the current XMLNode
+- void deleteText(XMLCSTR lpszValue); ///< Delete the text content "lpszValue" inside the current XMLNode (direct "pointer-to-pointer" comparison is used to find the right text)
+- void deleteClear(int i=0); ///< Delete the Ith clear tag inside the current XMLNode
+- void deleteClear(XMLCSTR lpszValue); ///< Delete the clear tag "lpszValue" inside the current XMLNode (direct "pointer-to-pointer" comparison is used to find the clear tag)
+- void deleteClear(XMLClear *p); ///< Delete the clear tag "p" inside the current XMLNode (direct "pointer-to-pointer" comparison on the lpszName of the clear tag is used to find the clear tag)
+- /** @} */
+-
+- /** @defgroup xmlWOSD ???_WOSD functions.
+- * @ingroup xmlModify
+- * The strings given as parameters for the "add" and "update" methods that have a name with
+- * the postfix "_WOSD" (that means "WithOut String Duplication")(for example "addText_WOSD")
+- * will be free'd by the XMLNode class. For example, it means that this is incorrect:
+- * \code
+- * xNode.addText_WOSD("foo");
+- * xNode.updateAttribute_WOSD("#newcolor" ,NULL,"color");
+- * \endcode
+- * In opposition, this is correct:
+- * \code
+- * xNode.addText("foo");
+- * xNode.addText_WOSD(stringDup("foo"));
+- * xNode.updateAttribute("#newcolor" ,NULL,"color");
+- * xNode.updateAttribute_WOSD(stringDup("#newcolor"),NULL,"color");
+- * \endcode
+- * Typically, you will never do:
+- * \code
+- * char *b=(char*)malloc(...);
+- * xNode.addText(b);
+- * free(b);
+- * \endcode
+- * ... but rather:
+- * \code
+- * char *b=(char*)malloc(...);
+- * xNode.addText_WOSD(b);
+- * \endcode
+- * ('free(b)' is performed by the XMLNode class)
+- * @{ */
+- static XMLNode createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration=FALSE); ///< Create the top node of an XMLNode structure
+- XMLNode addChild_WOSD(XMLSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1); ///< Add a new child node
+- XMLAttribute *addAttribute_WOSD(XMLSTR lpszName, XMLSTR lpszValue); ///< Add a new attribute
+- XMLCSTR addText_WOSD(XMLSTR lpszValue, XMLElementPosition pos=-1); ///< Add a new text content
+- XMLClear *addClear_WOSD(XMLSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, XMLElementPosition pos=-1); ///< Add a new clear Tag
+-
+- XMLCSTR updateName_WOSD(XMLSTR lpszName); ///< change node's name
+- XMLAttribute *updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); ///< if the attribute to update is missing, a new one will be added
+- XMLAttribute *updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName=NULL,int i=0); ///< if the attribute to update is missing, a new one will be added
+- XMLAttribute *updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName,XMLCSTR lpszOldName); ///< set lpszNewName=NULL if you don't want to change the name of the attribute if the attribute to update is missing, a new one will be added
+- XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, int i=0); ///< if the text to update is missing, a new one will be added
+- XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one will be added
+- XMLClear *updateClear_WOSD(XMLSTR lpszNewContent, int i=0); ///< if the clearTag to update is missing, a new one will be added
+- XMLClear *updateClear_WOSD(XMLClear *newP,XMLClear *oldP); ///< if the clearTag to update is missing, a new one will be added
+- XMLClear *updateClear_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new one will be added
+- /** @} */
+-
+- /** @defgroup xmlPosition Position helper functions (use in conjunction with the update&add functions
+- * @ingroup xmlModify
+- * These are some useful functions when you want to insert a childNode, a text or a XMLClearTag in the
+- * middle (at a specified position) of a XMLNode tree already constructed. The value returned by these
+- * methods is to be used as last parameter (parameter 'pos') of addChild, addText or addClear.
+- * @{ */
+- XMLElementPosition positionOfText(int i=0) const;
+- XMLElementPosition positionOfText(XMLCSTR lpszValue) const;
+- XMLElementPosition positionOfClear(int i=0) const;
+- XMLElementPosition positionOfClear(XMLCSTR lpszValue) const;
+- XMLElementPosition positionOfClear(XMLClear *a) const;
+- XMLElementPosition positionOfChildNode(int i=0) const;
+- XMLElementPosition positionOfChildNode(XMLNode x) const;
+- XMLElementPosition positionOfChildNode(XMLCSTR name, int i=0) const; ///< return the position of the ith childNode with the specified name if (name==NULL) return the position of the ith childNode
+- /** @} */
+-
+- /// Enumeration for XML character encoding.
+- typedef enum XMLCharEncoding
+- {
+- char_encoding_error=0,
+- char_encoding_UTF8=1,
+- char_encoding_legacy=2,
+- char_encoding_ShiftJIS=3,
+- char_encoding_GB2312=4,
+- char_encoding_Big5=5,
+- char_encoding_GBK=6 // this is actually the same as Big5
+- } XMLCharEncoding;
+-
+- /** \addtogroup conversions
+- * @{ */
+-
+- /// Sets the global options for the conversions
+- static char setGlobalOptions(XMLCharEncoding characterEncoding=XMLNode::char_encoding_UTF8, char guessWideCharChars=1,
+- char dropWhiteSpace=1, char removeCommentsInMiddleOfText=1);
+- /**< The "setGlobalOptions" function allows you to change four global parameters that affect string & file
+- * parsing. First of all, you most-probably will never have to change these 3 global parameters.
+- *
+- * @param guessWideCharChars If "guessWideCharChars"=1 and if this library is compiled in WideChar mode, then the
+- * XMLNode::parseFile and XMLNode::openFileHelper functions will test if the file contains ASCII
+- * characters. If this is the case, then the file will be loaded and converted in memory to
+- * WideChar before being parsed. If 0, no conversion will be performed.
+- *
+- * @param guessWideCharChars If "guessWideCharChars"=1 and if this library is compiled in ASCII/UTF8/char* mode, then the
+- * XMLNode::parseFile and XMLNode::openFileHelper functions will test if the file contains WideChar
+- * characters. If this is the case, then the file will be loaded and converted in memory to
+- * ASCII/UTF8/char* before being parsed. If 0, no conversion will be performed.
+- *
+- * @param characterEncoding This parameter is only meaningful when compiling in char* mode (multibyte character mode).
+- * In wchar_t* (wide char mode), this parameter is ignored. This parameter should be one of the
+- * three currently recognized encodings: XMLNode::encoding_UTF8, XMLNode::encoding_ascii,
+- * XMLNode::encoding_ShiftJIS.
+- *
+- * @param dropWhiteSpace In most situations, text fields containing only white spaces (and carriage returns)
+- * are useless. Even more, these "empty" text fields are annoying because they increase the
+- * complexity of the user's code for parsing. So, 99% of the time, it's better to drop
+- * the "empty" text fields. However The XML specification indicates that no white spaces
+- * should be lost when parsing the file. So to be perfectly XML-compliant, you should set
+- * dropWhiteSpace=0. A note of caution: if you set "dropWhiteSpace=0", the parser will be
+- * slower and your code will be more complex.
+- *
+- * @param removeCommentsInMiddleOfText To explain this parameter, let's consider this code:
+- * \code
+- * XMLNode x=XMLNode::parseString("foobarchu","a");
+- * \endcode
+- * If removeCommentsInMiddleOfText=0, then we will have:
+- * \code
+- * x.getText(0) -> "foo"
+- * x.getText(1) -> "bar"
+- * x.getText(2) -> "chu"
+- * x.getClear(0) --> ""
+- * x.getClear(1) --> ""
+- * \endcode
+- * If removeCommentsInMiddleOfText=1, then we will have:
+- * \code
+- * x.getText(0) -> "foobar"
+- * x.getText(1) -> "chu"
+- * x.getClear(0) --> ""
+- * \endcode
+- *
+- * \return "0" when there are no errors. If you try to set an unrecognized encoding then the return value will be "1" to signal an error.
+- *
+- * \note Sometime, it's useful to set "guessWideCharChars=0" to disable any conversion
+- * because the test to detect the file-type (ASCII/UTF8/char* or WideChar) may fail (rarely). */
+-
+- /// Guess the character encoding of the string (ascii, utf8 or shift-JIS)
+- static XMLCharEncoding guessCharEncoding(void *buffer, int bufLen, char useXMLEncodingAttribute=1);
+- /**< The "guessCharEncoding" function try to guess the character encoding. You most-probably will never
+- * have to use this function. It then returns the appropriate value of the global parameter
+- * "characterEncoding" described in the XMLNode::setGlobalOptions. The guess is based on the content of a buffer of length
+- * "bufLen" bytes that contains the first bytes (minimum 25 bytes; 200 bytes is a good value) of the
+- * file to be parsed. The XMLNode::openFileHelper function is using this function to automatically compute
+- * the value of the "characterEncoding" global parameter. There are several heuristics used to do the
+- * guess. One of the heuristic is based on the "encoding" attribute. The original XML specifications
+- * forbids to use this attribute to do the guess but you can still use it if you set
+- * "useXMLEncodingAttribute" to 1 (this is the default behavior and the behavior of most parsers).
+- * If an inconsistency in the encoding is detected, then the return value is "0". */
+- /** @} */
+-
+- private:
+- // these are functions and structures used internally by the XMLNode class (don't bother about them):
+-
+- typedef struct XMLNodeDataTag // to allow shallow copy and "intelligent/smart" pointers (automatic delete):
+- {
+- XMLCSTR lpszName; // Element name (=NULL if root)
+- int nChild, // Number of child nodes
+- nText, // Number of text fields
+- nClear, // Number of Clear fields (comments)
+- nAttribute; // Number of attributes
+- char isDeclaration; // Whether node is an XML declaration - ''
+- struct XMLNodeDataTag *pParent; // Pointer to parent element (=NULL if root)
+- XMLNode *pChild; // Array of child nodes
+- XMLCSTR *pText; // Array of text fields
+- XMLClear *pClear; // Array of clear fields
+- XMLAttribute *pAttribute; // Array of attributes
+- int *pOrder; // order of the child_nodes,text_fields,clear_fields
+- int ref_count; // for garbage collection (smart pointers)
+- } XMLNodeData;
+- XMLNodeData *d;
+-
+- char parseClearTag(void *px, void *pa);
+- char maybeAddTxT(void *pa, XMLCSTR tokenPStr);
+- int ParseXMLElement(void *pXML);
+- void *addToOrder(int memInc, int *_pos, int nc, void *p, int size, XMLElementType xtype);
+- int indexText(XMLCSTR lpszValue) const;
+- int indexClear(XMLCSTR lpszValue) const;
+- XMLNode addChild_priv(int,XMLSTR,char,int);
+- XMLAttribute *addAttribute_priv(int,XMLSTR,XMLSTR);
+- XMLCSTR addText_priv(int,XMLSTR,int);
+- XMLClear *addClear_priv(int,XMLSTR,XMLCSTR,XMLCSTR,int);
+- void emptyTheNode(char force);
+- static inline XMLElementPosition findPosition(XMLNodeData *d, int index, XMLElementType xtype);
+- static int CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat);
+- static int removeOrderElement(XMLNodeData *d, XMLElementType t, int index);
+- static void exactMemory(XMLNodeData *d);
+- static int detachFromParent(XMLNodeData *d);
+-} XMLNode;
+-
+-/// This structure is given by the function XMLNode::enumContents.
+-typedef struct XMLNodeContents
++inline bool operator== (const XMLNode &lhs, const XMLNode &rhs)
+ {
+- /// This dictates what's the content of the XMLNodeContent
+- enum XMLElementType etype;
+- /**< should be an union to access the appropriate data. Compiler does not allow union of object with constructor... too bad. */
+- XMLNode child;
+- XMLAttribute attrib;
+- XMLCSTR text;
+- XMLClear clear;
+-
+-} XMLNodeContents;
+-
+-/** @defgroup StringAlloc String Allocation/Free functions
+- * @ingroup xmlModify
+- * @{ */
+-/// Duplicate (copy in a new allocated buffer) the source string.
+-XMLDLLENTRY XMLSTR stringDup(XMLCSTR source, int cbData=-1);
+-/**< This is
+- * a very handy function when used with all the "XMLNode::*_WOSD" functions (\link xmlWOSD \endlink).
+- * @param cbData If !=0 then cbData is the number of chars to duplicate. New strings allocated with
+- * this function should be free'd using the "freeXMLString" function. */
++ return (lhs.mNode == rhs.mNode);
++}
+
+-/// to free the string allocated inside the "stringDup" function or the "createXMLString" function.
+-XMLDLLENTRY void freeXMLString(XMLSTR t); // {free(t);}
+-/** @} */
+-
+-/** @defgroup atoX ato? like functions
+- * @ingroup XMLParserGeneral
+- * The "xmlto?" functions are equivalents to the atoi, atol, atof functions.
+- * The only difference is: If the variable "xmlString" is NULL, than the return value
+- * is "defautValue". These 6 functions are only here as "convenience" functions for the
+- * user (they are not used inside the XMLparser). If you don't need them, you can
+- * delete them without any trouble.
+- *
+- * @{ */
+-XMLDLLENTRY char xmltob(XMLCSTR xmlString,char defautValue=0);
+-XMLDLLENTRY int xmltoi(XMLCSTR xmlString,int defautValue=0);
+-XMLDLLENTRY long xmltol(XMLCSTR xmlString,long defautValue=0);
+-XMLDLLENTRY double xmltof(XMLCSTR xmlString,double defautValue=.0);
+-XMLDLLENTRY XMLCSTR xmltoa(XMLCSTR xmlString,XMLCSTR defautValue=_CXML(""));
+-XMLDLLENTRY XMLCHAR xmltoc(XMLCSTR xmlString,const XMLCHAR defautValue=_CXML('\0'));
+-/** @} */
+-
+-/** @defgroup ToXMLStringTool Helper class to create XML files using "printf", "fprintf", "cout",... functions.
+- * @ingroup XMLParserGeneral
+- * @{ */
+-/// Helper class to create XML files using "printf", "fprintf", "cout",... functions.
+-/** The ToXMLStringTool class helps you creating XML files using "printf", "fprintf", "cout",... functions.
+- * The "ToXMLStringTool" class is processing strings so that all the characters
+- * &,",',<,> are replaced by their XML equivalent:
+- * \verbatim &, ", ', <, > \endverbatim
+- * Using the "ToXMLStringTool class" and the "fprintf function" is THE most efficient
+- * way to produce VERY large XML documents VERY fast.
+- * \note If you are creating from scratch an XML file using the provided XMLNode class
+- * you must not use the "ToXMLStringTool" class (because the "XMLNode" class does the
+- * processing job for you during rendering).*/
+-typedef struct XMLDLLENTRY ToXMLStringTool
++inline bool operator!= (const XMLNode &lhs, const XMLNode &rhs)
+ {
+-public:
+- ToXMLStringTool(): buf(NULL),buflen(0){}
+- ~ToXMLStringTool();
+- void freeBuffer();///name);
++ }
++
++ std::string value() const {
++ return std::string((const char *)mAttr->children->content);
++ }
++ const XMLAttribute next() const {
++ return XMLAttribute(mAttr->next);
++ }
++
++ friend const XMLAttribute XMLNode::getAttribute(const char *name) const;
++
++ private:
++ XMLAttribute(xmlAttrPtr attr): mAttr(attr) {};
++ xmlAttrPtr mAttr;
++};
+
+ #endif
+diff --git a/libmusicbrainz5.pc.cmake b/libmusicbrainz5.pc.cmake
+index c2f45c9..fca0de1 100644
+--- a/libmusicbrainz5.pc.cmake
++++ b/libmusicbrainz5.pc.cmake
+@@ -8,6 +8,7 @@ Description: The Musicbrainz Client Library.
+ URL: http://musicbrainz.org/doc/libmusicbrainz
+ Version: ${PROJECT_VERSION}
+ Requires.private: neon >= 0.25
++Requires: libxml-2.0
+ Libs: -L${LIB_INSTALL_DIR} -lmusicbrainz5
+ Cflags: -I${INCLUDE_INSTALL_DIR}
+
+diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
+index 2ee102f..368dd93 100644
+--- a/src/CMakeLists.txt
++++ b/src/CMakeLists.txt
+@@ -1,14 +1,15 @@
+ SET(CMAKE_INCLUDE_CURRENT_DIR ON)
+-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../include ${NEON_INCLUDE_DIR})
++INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../include ${NEON_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})
+
+ SET(_sources Alias.cc Annotation.cc Artist.cc ArtistCredit.cc Attribute.cc CDStub.cc Collection.cc
+ Disc.cc Entity.cc FreeDBDisc.cc HTTPFetch.cc ISRC.cc Label.cc LabelInfo.cc Lifespan.cc List.cc
+ mb5_c.cc Medium.cc MediumList.cc Message.cc Metadata.cc NameCredit.cc NonMBTrack.cc PUID.cc
+ Query.cc Rating.cc Recording.cc Relation.cc RelationList.cc Release.cc ReleaseGroup.cc Tag.cc
+- TextRepresentation.cc Track.cc UserRating.cc UserTag.cc Work.cc xmlParser.cpp
++ TextRepresentation.cc Track.cc UserRating.cc UserTag.cc Work.cc xmlParser.cc
+ RelationListList.cc ISWCList.cc ISWC.cc SecondaryType.cc SecondaryTypeList.cc IPI.cc)
+
+-ADD_EXECUTABLE(make-c-interface make-c-interface.cc xmlParser.cpp)
++ADD_EXECUTABLE(make-c-interface make-c-interface.cc xmlParser.cc)
++TARGET_LINK_LIBRARIES(make-c-interface ${LIBXML2_LIBRARIES})
+
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mb5_c.cc ${CMAKE_CURRENT_BINARY_DIR}/mb5_c.h ${CMAKE_CURRENT_BINARY_DIR}/../include/musicbrainz5/mb5_c.h
+@@ -36,7 +37,7 @@ if(CMAKE_BUILD_TYPE STREQUAL Debug)
+ ENDIF(CMAKE_COMPILER_IS_GNUCXX)
+ endif(CMAKE_BUILD_TYPE STREQUAL Debug)
+
+-TARGET_LINK_LIBRARIES(musicbrainz5 ${NEON_LIBRARIES})
++TARGET_LINK_LIBRARIES(musicbrainz5 ${NEON_LIBRARIES} ${LIBXML2_LIBRARIES})
+
+ IF(WIN32)
+ TARGET_LINK_LIBRARIES(musicbrainz5 wsock32 winmm ws2_32)
+@@ -47,7 +48,7 @@ IF(CMAKE_COMPILER_IS_GNUCXX)
+ IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../.git)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
+ ENDIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../.git)
+- set_source_files_properties(mb5_c.cc PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations")
++ #set_source_files_properties(mb5_c.cc PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations")
+ ENDIF(CMAKE_COMPILER_IS_GNUCXX)
+
+ INSTALL(TARGETS musicbrainz5 DESTINATION ${LIB_INSTALL_DIR})
+diff --git a/src/Entity.cc b/src/Entity.cc
+index 0644377..a1bb1ca 100644
+--- a/src/Entity.cc
++++ b/src/Entity.cc
+@@ -80,10 +80,12 @@ void MusicBrainz5::CEntity::Parse(const XMLNode& Node)
+ {
+ if (!Node.isEmpty())
+ {
+- for (int count=0;countm_ExtAttributes[Name.substr(4)]=Value;
+@@ -93,10 +95,10 @@ void MusicBrainz5::CEntity::Parse(const XMLNode& Node)
+
+ //std::cout << "Node: " << std::endl << Node.createXMLString(true) << std::endl;
+
+- for (int count=0;count
+
+
+@@ -218,7 +216,7 @@ extern "C"
+
+
+
+-
++
+
+
+
+diff --git a/src/make-c-interface.cc b/src/make-c-interface.cc
+index 652a65b..97af3d9 100644
+--- a/src/make-c-interface.cc
++++ b/src/make-c-interface.cc
+@@ -28,6 +28,8 @@
+ #include
+ #include
+ #include
++#include
++#include
+ #include
+ #include
+
+@@ -51,8 +53,9 @@ int main(int argc, const char *argv[])
+ {
+ std::string XMLFile=std::string(argv[1])+"/"+argv[2];
+ XMLResults Results;
+- XMLNode TopNode=XMLNode::parseFile(XMLFile.c_str(),"cinterface",&Results);
+- if (!TopNode.isEmpty())
++ XMLNode *TopNode=XMLRootNode::parseFile(XMLFile.c_str(),&Results);
++ memset(&Results, 0, sizeof(Results));
++ if (!TopNode->isEmpty())
+ {
+ std::cout << "Generating '" << argv[3] << "/" << argv[4] << "' and '" << argv[3] << "/" << argv[5] << "'" << std::endl;
+
+@@ -74,9 +77,10 @@ int main(int argc, const char *argv[])
+ return 1;
+ }
+
+- for (int count=0;countgetChildNode();
++ !Node.isEmpty();
++ Node = Node.next())
+ {
+- XMLNode Node=TopNode.getChildNode(count);
+ std::string Name=Node.getName();
+
+ if ("boilerplate"==Name)
+@@ -84,7 +88,7 @@ int main(int argc, const char *argv[])
+ else if ("header"==Name)
+ ProcessHeader(Node,Source,Include);
+ else if ("declare"==Name)
+- ProcessDeclare(TopNode,Source,Include);
++ ProcessDeclare(*TopNode,Source,Include);
+ else if ("entity"==Name)
+ ProcessEntity(Node,Source,Include);
+ else if ("class"==Name)
+@@ -100,9 +104,11 @@ int main(int argc, const char *argv[])
+ }
+ else
+ {
+- std::cerr << "Error reading XML: " << XMLNode::getError(Results.error) << " at line " << Results.nLine << std::endl;
++ std::cerr << "Error reading XML: " << Results.message << " at line " << Results.line << std::endl;
+ return 1;
+ }
++ if (TopNode != NULL)
++ delete TopNode;
+ }
+
+ return 0;
+@@ -114,7 +120,7 @@ std::ofstream *GetFile(const XMLNode& Node, std::ofstream& Source, std::ofstream
+
+ if (Node.isAttributeSet("target"))
+ {
+- std::string Target=Node.getAttribute("target");
++ std::string Target=Node.getAttribute("target").value();
+ if ("source"==Target)
+ File=&Source;
+ else if ("include"==Target)
+@@ -162,7 +168,7 @@ void ProcessBoilerplate(const XMLNode& Node, std::ofstream& Source, std::ofstrea
+
+ if (Node.isAttributeSet("file"))
+ {
+- std::string FileName=Node.getAttribute("file");
++ std::string FileName=Node.getAttribute("file").value();
+ std::ifstream InFile(FileName.c_str());
+ if (InFile.is_open())
+ *File << InFile.rdbuf() << std::endl;
+@@ -263,11 +269,11 @@ void ProcessClass(const XMLNode& Node, std::ofstream& Source, std::ofstream& Inc
+ {
+ if (Node.isAttributeSet("name"))
+ {
+- std::string LowerName=Node.getAttribute("name");
++ std::string LowerName=Node.getAttribute("name").value();
+
+ std::string UpperName=LowerName;
+ if (Node.isAttributeSet("uppername"))
+- UpperName=Node.getAttribute("uppername");
++ UpperName=Node.getAttribute("uppername").value();
+ else
+ UpperName[0]=toupper(UpperName[0]);
+
+@@ -294,24 +300,25 @@ void ProcessClass(const XMLNode& Node, std::ofstream& Source, std::ofstream& Inc
+
+ Source << " MB5_C_CLONE(" << UpperName << "," << LowerName << ")" << std::endl;
+
+- for (int count=0;count Classes;
+ Classes.push_back("Entity");
+
+- for (int count=0;count.
++
++ $Id$
++
++----------------------------------------------------------------------------*/
++
++#include "config.h"
++#include "musicbrainz5/defines.h"
++
++#include "musicbrainz5/xmlParser.h"
++
++#include
++
++XMLNode XMLNode::emptyNode()
++{
++ return XMLNode(NULL);
++}
++
++XMLNode *XMLRootNode::parseFile(const std::string &filename, xmlErrorPtr results)
++{
++ xmlDocPtr doc;
++
++ doc = xmlParseFile(filename.c_str());
++ if ((doc == NULL) && (results != NULL)) {
++ xmlCopyError(xmlGetLastError(), results);
++ }
++
++ return new XMLRootNode(doc);
++}
++
++XMLNode *XMLRootNode::parseString(std::string &xml, xmlErrorPtr results)
++{
++ xmlDocPtr doc;
++
++ doc = xmlParseMemory(xml.c_str(), xml.length());
++ if ((doc == NULL) && (results != NULL)) {
++ xmlCopyError(xmlGetLastError(), results);
++ }
++
++ return new XMLRootNode(doc);
++}
++
++const char *XMLNode::getName() const
++{
++ return (char *)mNode->name;
++}
++
++const char *XMLNode::getText() const
++{
++ if (mNode->children == NULL)
++ return NULL;
++ if (!xmlNodeIsText(mNode->children))
++ return NULL;
++
++ return (char*)mNode->children->content;
++}
++
++xmlAttrPtr XMLNode::getAttributeRaw(const char *name) const
++{
++ xmlAttrPtr attr;
++
++ for (attr = mNode->properties; attr != NULL; attr = attr->next)
++ if (strcmp(name, (char *)attr->name) == 0)
++ return attr;
++
++ return NULL;
++}
++
++const XMLAttribute XMLNode::getAttribute(const char *name) const
++{
++ xmlAttrPtr attr;
++
++ if (name == NULL)
++ return XMLAttribute(mNode->properties);
++
++ attr = this->getAttributeRaw(name);
++ if (attr != NULL)
++ return XMLAttribute(attr);
++
++ return XMLAttribute(NULL);
++}
++
++bool XMLNode::isAttributeSet(const char *name) const
++{
++ return (this->getAttributeRaw(name) != NULL);
++}
++
++XMLRootNode::XMLRootNode(xmlDocPtr doc): XMLNode(xmlDocGetRootElement(doc)),
++ mDoc(doc)
++{
++}
++
++static xmlNodePtr skipTextNodes(xmlNodePtr node)
++{
++ xmlNodePtr it = node;
++
++ while ((it != NULL) && xmlNodeIsText(it))
++ it = it->next;
++
++ return it;
++}
++
++XMLNode XMLNode::next() const
++{
++ return XMLNode(skipTextNodes(mNode->next));
++}
++
++XMLNode XMLNode::getChildNode(const char *name) const
++{
++ xmlNodePtr it;
++ if (name == NULL)
++ return XMLNode(skipTextNodes(mNode->children));
++
++ for (it = mNode->children; it != NULL; it = it->next) {
++ if (xmlNodeIsText(it))
++ continue;
++ if (strcmp(name, (char *)it->name) == 0)
++ return XMLNode(it);
++ }
++
++ return emptyNode();
++}
++
++bool XMLNode::isEmpty() const
++{
++ return mNode == NULL;
++}
+diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
+index 645f8ae..8dd569c 100644
+--- a/tests/CMakeLists.txt
++++ b/tests/CMakeLists.txt
+@@ -1,5 +1,5 @@
+-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include)
+-LINK_LIBRARIES(musicbrainz5 ${NEON_LIBRARIES})
++INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include ${LIBXML2_INCLUDE_DIR})
++LINK_LIBRARIES(musicbrainz5 ${NEON_LIBRARIES} ${LIBXML2_LIBRARIES})
+ ADD_EXECUTABLE(mbtest mbtest.cc)
+ ADD_EXECUTABLE(ctest ctest.c)
+
diff --git a/SPECS/libmusicbrainz5.spec b/SPECS/libmusicbrainz5.spec
new file mode 100644
index 0000000..367f3d4
--- /dev/null
+++ b/SPECS/libmusicbrainz5.spec
@@ -0,0 +1,283 @@
+
+# Fedora package review: http://bugzilla.redhat.com/718395
+
+Summary: Library for accessing MusicBrainz servers
+Name: libmusicbrainz5
+Version: 5.0.1
+Release: 9%{?dist}
+License: LGPLv2
+Group: System Environment/Libraries
+URL: http://www.musicbrainz.org/
+# Source0: https://github.com/downloads/metabrainz/libmusicbrainz/libmusicbrainz-%{version}.tar.gz
+# We need to remove src/xmlParser.cpp, as it is non-free and prohibits commercial distribution.
+# Just unpack and rm -rf src/xmlParser.cpp, then
+# tar cfz libmusicbrainz-%{version}-clean.tar.gz libmusicbrainz-%{version}/
+Source0: libmusicbrainz-%{version}-clean.tar.gz
+# This patch replaces the removed src/xmlParser.cpp support with libxml2
+# and fixes up the cinterface.xml file (libxml2 seems to be stricter).
+Patch0: 0001-xmlparsing.patch
+BuildRequires: cmake
+BuildRequires: doxygen
+BuildRequires: neon-devel
+BuildRequires: libxml2-devel
+Obsoletes: libmusicbrainz4 < 4.0.3-5
+
+%description
+The MusicBrainz client library allows applications to make metadata
+lookup to a MusicBrainz server, generate signatures from WAV data and
+create CD Index Disk ids from audio CD roms.
+
+%package devel
+Summary: Headers for developing programs that will use %{name}
+Group: Development/Libraries
+Requires: %{name}%{?_isa} = %{version}-%{release}
+Obsoletes: libmusicbrainz4-devel < 4.0.3-5
+
+%description devel
+This package contains the headers that programmers will need to develop
+applications which will use %{name}.
+
+
+%prep
+%setup -q -n libmusicbrainz-%{version}
+%patch0 -p1 -b .xmlParser
+
+# omit "Generated on ..." timestamps that induce multilib conflicts
+# this is *supposed* to be the doxygen default in fedora these days, but
+# it seems there's still a bug or 2 there -- Rex
+echo "HTML_TIMESTAMP = NO" >> Doxyfile.cmake
+
+
+%build
+%{cmake} .
+
+make %{?_smp_mflags} V=1
+make %{?_smp_mflags} docs
+
+
+%install
+
+make install/fast DESTDIR=%{buildroot}
+
+rm -f docs/installdox
+
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+
+%files
+%doc AUTHORS.txt COPYING.txt NEWS.txt README.md
+%{_libdir}/libmusicbrainz5.so.0*
+
+%files devel
+%doc docs/*
+%{_includedir}/musicbrainz5/
+%{_libdir}/libmusicbrainz5.so
+%{_libdir}/pkgconfig/libmusicbrainz5.pc
+
+
+%changelog
+* Fri Jan 24 2014 Daniel Mach - 5.0.1-9
+- Mass rebuild 2014-01-24
+
+* Fri Dec 27 2013 Daniel Mach - 5.0.1-8
+- Mass rebuild 2013-12-27
+
+* Wed Jun 12 2013 Kalev Lember - 5.0.1-7
+- Fix the libmusicbrainz4 obsoletes version
+
+* Tue Jun 11 2013 Christophe Fergeau 5.0.1-6
+- Obsoletes libmusicbrainz4, fixes rhbz#967322
+
+* Wed Apr 03 2013 Christophe Fergeau - 5.0.1-5
+- Fix Patch1 which is causing rhbz#845846
+
+* Thu Feb 14 2013 Fedora Release Engineering - 5.0.1-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Mon Jan 7 2013 Tom Callaway - 5.0.1-3
+- remove non-free xmlParser.cpp
+
+* Mon Aug 27 2012 Christophe Fergeau - 5.0.1-2
+- Address review comments (rhbz#832670)
+ fix licence (LGPLv2+ -> LGPLv2)
+ fix tarball URL
+ remove obsolete use of RPM_BUILD_ROOT
+ remove BuildRequires on pkg-config
+ remove use of %%defattr
+
+* Sat Jun 16 2012 Christophe Fergeau - 5.0.1-1
+- Package libmusicbrainz5, apart from the name/version it's identical to
+ libmusicbrainz4 so this .spec is based on it.
+
+* Wed May 16 2012 Christophe Fergeau - 4.0.3-1
+- New upstream 4.0.3 release, should fix a bug breaking metadata fetching
+ from musicbrainz servers
+
+* Fri Apr 20 2012 Christophe Fergeau - 4.0.1-1
+- New upstream 4.0.1 release, drop patch that has been merged upstream
+
+* Sun Mar 04 2012 Christophe Fergeau - 4.0.0-1
+- First pass at a libmusicbrainz4 package, heavily based on the
+ libmusicbrainz3 package
+
+* Fri Jan 13 2012 Fedora Release Engineering - 3.0.3-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Tue Feb 08 2011 Fedora Release Engineering - 3.0.3-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Mon Oct 18 2010 Rex Dieter 3.0.3-2
+- libmusicbrainz3-devel multilib conflict (#480378)
+- drop extraneous pkgconfig dep baggage
+
+* Mon Oct 18 2010 Bastien Nocera 3.0.3-1
+- Update to 3.0.3 (#643789)
+
+* Tue May 25 2010 Bastien Nocera 3.0.2-7
+- Remove script from devel docs
+
+* Tue Nov 03 2009 Rex Dieter - 3.0.2-7
+- fix/enable unit tests
+
+* Fri Jul 24 2009 Fedora Release Engineering - 3.0.2-6
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Mon Jun 29 2009 Rex Dieter - 3.0.2-5
+- fix doxygen-induced multilib conflicts (#480378)
+- add %%check section (disabled by default, pending cppunit detection issues)
+
+* Wed Feb 25 2009 Rex Dieter - 3.0.2-4
+- work harder to omit extraneous pkgconfig deps
+- gcc44 patch
+
+* Wed Feb 25 2009 Fedora Release Engineering - 3.0.2-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
+
+* Fri Dec 12 2008 Rex Dieter 3.0.2-2
+- rebuild for pkgconfig deps
+
+* Tue Sep 16 2008 Rex Dieter 3.0.2-1
+- libmusicbrainz3-3.0.2
+
+* Fri Sep 05 2008 Rex Dieter 3.0.1-4
+- Build docs (#461238)
+- -devel: drop extraneous Requires
+
+* Fri Jul 25 2008 Rex Dieter 3.0.1-3
+- fix recursive linking against libdiscid neon
+
+* Thu Jul 24 2008 Rex Dieter 3.0.1-2
+- BR: libdiscid-devel
+- -devel: Requires: libdiscid-devel neon-devel
+
+* Mon Jun 16 2008 Rex Dieter 3.0.1-1
+- libmusicbrainz3-3.0.1
+
+* Sun Jun 15 2008 Rex Dieter 2.1.5-7
+- Provides: libmusicbrainz2(-devel), prepare for libmusicbrainz3
+
+* Fri Feb 22 2008 Rex Dieter 2.1.5-6
+- gcc43 patch (#434127)
+
+* Mon Feb 18 2008 Fedora Release Engineering - 2.1.5-5
+- Autorebuild for GCC 4.3
+
+* Mon Feb 18 2008 Rex Dieter - 2.1.5-4
+- specfile cosmetics
+
+* Thu Nov 15 2007 Rex Dieter - 2.1.5-3
+- use versioned Obsoletes
+- drop (Build)Requires: libstdc++-devel
+- License: LGPLv2+
+
+* Fri Aug 24 2007 Adam Jackson - 2.1.5-2
+- Rebuild for PPC toolchain bug
+
+* Thu Jun 21 2007 - Bastien Nocera - 2.1.5-1
+- Update to 2.1.5
+
+* Mon Oct 23 2006 Matthias Clasen - 2.1.4-1
+- Update to 2.1.4
+
+* Wed Jul 12 2006 Jesse Keating - 2.1.1-4.1
+- rebuild
+
+* Wed Jun 7 2006 Jeremy Katz - 2.1.1-4
+- rebuild for -devel deps
+
+* Tue Apr 18 2006 Matthias Clasen - 2.1.1-3
+- apply .spec file cleanups from Matthias Saou (#172926)
+
+* Fri Feb 10 2006 Jesse Keating - 2.1.1-2.1
+- bump again for double-long bug on ppc(64)
+
+* Tue Feb 7 2006 Christopher Aillon - 2.1.1-2
+- Stop shipping the .a file in the main package
+
+* Tue Feb 07 2006 Jesse Keating - 2.1.1-1.2
+- rebuilt for new gcc4.1 snapshot and glibc changes
+
+* Fri Dec 09 2005 Jesse Keating
+- rebuilt
+
+* Wed Mar 23 2005 John (J5) Palmieri 2.1.1-1
+- Update to upstream version 2.1.1
+- Removed libmusicbrainz-2.0.2-missing-return.patch
+- Removed libmusicbrainz-2.0.2-conf.patch
+
+* Thu Mar 03 2005 John (J5) Palmieri 2.0.2-14
+- Add patch to fix percision cast error to compile correctly on s390x
+
+* Thu Mar 03 2005 John (J5) Palmieri 2.0.2-13
+- rebuild with gcc 4.0
+
+* Mon Nov 08 2004 Colin Walters 2.0.2-12
+- Add libmusicbrainz-2.0.2-missing-return.patch (bug #137289)
+
+* Thu Oct 07 2004 Colin Walters 2.0.2-11
+- BuildRequire expat-devel
+
+* Tue Sep 28 2004 Colin Walters 2.0.2-10
+- Move .so symlink to -devel package
+
+* Tue Aug 31 2004 Colin Walters 2.0.2-9
+- Add ldconfig calls (bz #131281)
+
+* Tue Jun 15 2004 Elliot Lee
+- rebuilt
+
+* Tue Mar 02 2004 Elliot Lee
+- rebuilt
+
+* Fri Feb 13 2004 Elliot Lee
+- rebuilt
+
+* Thu Dec 18 2003 Brent Fox 2.0.2-6
+- add a BuildPreReq for libstdc++-devel and gcc-c++ (bug #106556)
+- add a Requires for libstdc++-devel for libmusicbrainz-devel
+
+* Mon Sep 1 2003 Bill Nottingham
+- Obsoletes musicbrainz-devel too
+
+* Mon Sep 1 2003 Jonathan Blandford
+- Obsoletes musicbrainz
+
+* Fri Aug 22 2003 Bill Nottingham 2.0.2-5
+- fix autoconf/libtool weirdness, remove exclusivearch
+
+* Fri Aug 22 2003 Brent Fox 2.0.2-4
+- add ExcludeArch for s390x (something is really broken)
+
+* Fri Aug 22 2003 Brent Fox 2.0.2-3
+- add ExcludeArch for ppc64
+
+* Fri Aug 22 2003 Brent Fox 2.0.2-2
+- add ExcludeArch for x86_64 for now
+
+* Thu Aug 21 2003 Brent Fox
+- Initial build.
+
+