Wrapper pour les strings Xerces
Depuis peu, j'utilise la librarie XML Xerces d'Apache (pour le moment j'ai touché uniquement au DOM) et cette dernière est extrêmement puissante :- Rapide,
- API claire,
- Support des XPath,
- API assez proche du c# (Node, Element, même noms de méthodes),
- Multiplateforme,
- Validation des XSD,
- etc.
Comme j'ai pu déjà vous en parler dans un précédent post, je ne trouve pas ce type d'API très sexy car le code produit pour accéder au document XML est assez verbeux et cela est induit par la notion Node/Element/Attribute connue par les utilisateurs de C#.
Dans le cas d'un outil cela ne me gène pas beaucoup mais ce qui me chagrine plus dans le cas de Xerces est la manipulation de strings. En effet, mes premières lignes de code utilisant la librairie Xerces ressemblaient à cela :
XMLCh tempStr[100];Vous pouvez donc remarquer que la quantité code à produire pour récupérer la valeur d'un attribut est trop importante et rend le tout peu lisible. C'est pourquoi j'ai mis en place une classe pour gérer automatiquement la durée de vie et le buffer de travail des chaînes de caractères pour Xerces :
XMLString::transcode("Range", tempStr, 99);
XMLCh const * const pRangeValue = pMyElem->getAttribute(tempStr);
char const * const pValue = XMLString::transcode(pRangeValue);
// Do things
XMLString::release(&pValue);
template <unsigned int Size>
class CXercesString
{
public :
CXercesString (void);
~CXercesString (void);
CXercesString (char const * const pSrc);
CXercesString (XMLCh const * const pSrc);
CXercesString (CXercesString<Size> const & SrcStr);
CXercesString & operator = (char const * const pSrc);
CXercesString & operator = (XMLCh const * const pSrc);
CXercesString & operator = (CXercesString<Size> const & SrcStr);
char const * const GetCharArray(void) const;
XMLCh const * const GetXMLCh (void) const;
size_t GetLength (void) const;
void Clear (void);
protected :
char * m_pCharArray;
XMLCh m_pXercesStr[Size];
};
template <unsigned int Size>
CXercesString<Size> :: CXercesString (void) :
m_pCharArray(NULL)
{
memset(m_pXercesStr, 0, sizeof(XMLCh) * Size);
}
template <unsigned int Size>
CXercesString<Size> :: ~CXercesString (void)
{
if (m_pCharArray)
{
XMLString::release(&m_pCharArray);
}
}
template <unsigned int Size>
CXercesString<Size> :: CXercesString (char const * const pSrc)
{
assert(pSrc);
assert(Size > strlen(pSrc));
XMLString::transcode(pSrc, m_pXercesStr, Size - 1);
m_pCharArray = XMLString::transcode(m_pXercesStr);
}
template <unsigned int Size>
CXercesString<Size> :: CXercesString (XMLCh const * const pSrc)
{
assert(pSrc);
m_pCharArray = XMLString::transcode(pSrc);
assert(Size > strlen(m_pCharArray));
XMLString::transcode(m_pCharArray, m_pXercesStr, Size - 1);
}
template <unsigned int Size>
CXercesString<Size> :: CXercesString (CXercesString<Size> const & SrcStr) :
m_pCharArray(SrcStr.m_pCharArray)
{
if (m_pCharArray)
{
XMLString::transcode(m_pCharArray, m_pXercesStr, Size - 1);
}
else
{
memset(m_pXercesStr, 0, Size * sizeof(XMLCh));
}
}
template <unsigned int Size>
CXercesString<Size> & CXercesString<Size> :: operator = (char const * const pSrc)
{
assert(pSrc);
Clear();
m_pCharArray = pSrc;
if (m_pCharArray)
{
XMLString::transcode(m_pCharArray, m_pXercesStr, Size - 1);
}
else
{
memset(m_pXercesStr, 0, Size * sizeof(XMLCh));
}
return (*this);
}
template <unsigned int Size>
CXercesString<Size> & CXercesString<Size> :: operator = (XMLCh const * const pSrc)
{
assert(pSrc);
Clear();
m_pCharArray = XMLString::transcode(pSrc);
assert(Size > strlen(m_pCharArray));
XMLString::transcode(m_pCharArray, m_pXercesStr, Size - 1);
return (*this);
}
template <unsigned int Size>
CXercesString<Size> & CXercesString<Size> :: operator = (CXercesString<Size> const & SrcStr)
{
this->operator = (SrcStr.m_pCharArray);
return (*this);
}
template <unsigned int Size>
char const * const CXercesString<Size> :: GetCharArray(void) const
{
return (m_pCharArray);
}
template <unsigned int Size>
XMLCh const * const CXercesString<Size> :: GetXMLCh (void) const
{
return (&(m_pXercesStr[0]));
}
template <unsigned int Size>
size_t CXercesString<Size> :: GetLength (void) const
{
size_t StrSize = 0;
if (m_pCharArray)
{
StrSize = strlen(m_pCharArray);
}
return (StrSize);
}
template <unsigned int Size>
void CXercesString<Size> :: Clear (void)
{
if (m_pCharArray)
{
XMLString::release(&m_pCharArray);
}
m_pCharArray = NULL;
memset(m_pXercesStr, 0, Size * sizeof(XMLCh));
}
Le code précédent devient donc :
{
CXercesString<50> const RangeValue(pMyElem->getAttribute(CXercesString<10>("Range").GetXMLCh()));
}
J'ai codé la classe CXercesString assez rapidement donc, il doit y avoir quelques bugs et il est sûrement possible d'être plus performant ou de fournir une meilleure interface (cast, etc.) mais bon ... l'idée principale est là :)

Commentaires