[SCM] qgis branch, master, updated. a2ee769957385f4e084c5e8b6ba178a8c877d1db

Giuseppe Sucameli brush.tyler at gmail.com
Tue Mar 20 13:43:05 UTC 2012


The following commit has been merged in the master branch:
commit 39069220b21d2939356f54395a5a69cdd70a67da
Author: Giuseppe Sucameli <brush.tyler at gmail.com>
Date:   Thu Mar 8 05:02:44 2012 +0100

    [FEATURE] load/save layer style (new symbology) from/to SLD document
    
    This is a huge commit, but it's mostly new functions. It changes only few lines on the existing code.
    - add conversion between QgsExpression and OGC Filter Encoding 1.1
    - add conversion between QgsRendererV2 and OGC Symbology Encoding 1.1
    
    Work done for Regione Toscana-SIGTA

diff --git a/src/app/qgsvectorlayerproperties.cpp b/src/app/qgsvectorlayerproperties.cpp
index ea0cf06..3071594 100644
--- a/src/app/qgsvectorlayerproperties.cpp
+++ b/src/app/qgsvectorlayerproperties.cpp
@@ -950,14 +950,25 @@ void QgsVectorLayerProperties::on_pbnLoadStyle_clicked()
 {
   QSettings myQSettings;  // where we keep last used filter in persistent state
   QString myLastUsedDir = myQSettings.value( "style/lastStyleDir", "." ).toString();
-  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer properties from style file (.qml)" ), myLastUsedDir, tr( "QGIS Layer Style File (*.qml)" ) );
+  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer properties from style file" ), myLastUsedDir,
+                                                     tr( "QGIS Layer Style File (*.qml)" ) + ";;" + tr( "SLD File (*.sld)" ) );
   if ( myFileName.isNull() )
   {
     return;
   }
 
+  QString myMessage;
   bool defaultLoadedFlag = false;
-  QString myMessage = layer->loadNamedStyle( myFileName, defaultLoadedFlag );
+
+  if ( myFileName.endsWith( ".sld", Qt::CaseInsensitive ) )
+  {
+    // load from SLD
+     myMessage = layer->loadSldStyle( myFileName, defaultLoadedFlag );
+  }
+  else
+  {
+    myMessage = layer->loadNamedStyle( myFileName, defaultLoadedFlag );
+  }
   //reset if the default style was loaded ok only
   if ( defaultLoadedFlag )
   {
@@ -966,7 +977,7 @@ void QgsVectorLayerProperties::on_pbnLoadStyle_clicked()
   else
   {
     //let the user know what went wrong
-    QMessageBox::information( this, tr( "Saved Style" ), myMessage );
+    QMessageBox::information( this, tr( "Load Style" ), myMessage );
   }
 
   QFileInfo myFI( myFileName );
@@ -979,7 +990,8 @@ void QgsVectorLayerProperties::on_pbnSaveStyleAs_clicked()
 {
   QSettings myQSettings;  // where we keep last used filter in persistent state
   QString myLastUsedDir = myQSettings.value( "style/lastStyleDir", "." ).toString();
-  QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save layer properties as style file (.qml)" ), myLastUsedDir, tr( "QGIS Layer Style File (*.qml)" ) );
+  QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save layer properties as style file" ), myLastUsedDir,
+                                                           tr( "QGIS Layer Style File (*.qml)" ) + ";;" + tr( "SLD File (*.sld)" ) );
   if ( myOutputFileName.isNull() ) //dialog canceled
   {
     return;
@@ -987,14 +999,25 @@ void QgsVectorLayerProperties::on_pbnSaveStyleAs_clicked()
 
   apply(); // make sure the qml to save is uptodate
 
+  QString myMessage;
+  bool defaultLoadedFlag = false;
+
   //ensure the user never omitted the extension from the file name
-  if ( !myOutputFileName.endsWith( ".qml", Qt::CaseInsensitive ) )
+  if ( myOutputFileName.endsWith( ".sld", Qt::CaseInsensitive ) )
+  {
+    // convert to SLD
+     myMessage = layer->saveSldStyle( myOutputFileName, defaultLoadedFlag );
+  }
+  else
   {
-    myOutputFileName += ".qml";
+    if ( !myOutputFileName.endsWith( ".qml", Qt::CaseInsensitive ) )
+    {
+      myOutputFileName += ".qml";
+    }
+
+    myMessage = layer->saveNamedStyle( myOutputFileName, defaultLoadedFlag );
   }
 
-  bool defaultLoadedFlag = false;
-  QString myMessage = layer->saveNamedStyle( myOutputFileName, defaultLoadedFlag );
   //reset if the default style was loaded ok only
   if ( defaultLoadedFlag )
   {
diff --git a/src/core/qgsexpression.cpp b/src/core/qgsexpression.cpp
index 5bb7959..7531f52 100644
--- a/src/core/qgsexpression.cpp
+++ b/src/core/qgsexpression.cpp
@@ -25,6 +25,7 @@
 #include "qgsdistancearea.h"
 #include "qgsfeature.h"
 #include "qgsgeometry.h"
+#include "qgslogger.h"
 
 // from parser
 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg );
@@ -109,11 +110,27 @@ const char* QgsExpression::BinaryOperatorText[] =
   "||"
 };
 
+const char* QgsExpression::BinaryOgcOperatorText[] =
+{
+  "Or", "And",
+  "PropertyIsEqualTo", "PropertyIsNotEqualTo",
+  "PropertyIsGreaterThanOrEqualTo", "PropertyIsLessThanOrEqualTo",
+  "PropertyIsLessThan", "PropertyIsGreaterThan",
+  "", "PropertyIsLike", "", "", "",
+  "Add", "Sub", "Mul", "Div", "", "",
+  ""
+};
+
 const char* QgsExpression::UnaryOperatorText[] =
 {
   "NOT", "-"
 };
 
+const char* QgsExpression::UnaryOgcOperatorText[] =
+{
+  "Not", ""
+};
+
 ///////////////////////////////////////////////
 // functions
 
@@ -546,6 +563,49 @@ QString QgsExpression::dump() const
   return mRootNode->dump();
 }
 
+void QgsExpression::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
+{
+  if ( !mRootNode )
+    return;
+
+  mRootNode->toOgcFilter( doc, element );
+}
+
+QgsExpression* QgsExpression::createFromOgcFilter( QDomElement &element )
+{
+  if ( element.isNull() || !element.hasChildNodes() )
+    return NULL;
+
+  QgsExpression *expr = new QgsExpression();
+
+  QDomElement childElem = element.firstChildElement();
+  while ( !childElem.isNull() )
+  {
+    QString errorMsg;
+    QgsExpression::Node *node = QgsExpression::Node::createFromOgcFilter( childElem, errorMsg );
+    if ( !node )
+    {
+      // invalid expression, parser error
+      expr->mParserErrorString = errorMsg;
+      return expr;
+    }
+
+    // use the concat binary operator to append to the root node
+    if ( !expr->mRootNode )
+    {
+      expr->mRootNode = node;
+    }
+    else
+    {
+      expr->mRootNode = new QgsExpression::NodeBinaryOperator( boConcat, expr->mRootNode, node );
+    }
+
+    childElem = childElem.nextSiblingElement();
+  }
+
+  return expr;
+}
+
 void QgsExpression::acceptVisitor( QgsExpression::Visitor& v )
 {
   if ( mRootNode )
@@ -553,6 +613,116 @@ void QgsExpression::acceptVisitor( QgsExpression::Visitor& v )
 }
 
 
+QgsExpression::Node* QgsExpression::Node::createFromOgcFilter( QDomElement &element, QString &errorMessage )
+{
+  if ( element.isNull() )
+    return NULL;
+
+  // check for unary operators
+  int unaryOpCount = sizeof( UnaryOgcOperatorText ) / sizeof( UnaryOgcOperatorText[0] );
+  for ( int i = 0; i < unaryOpCount; i++ )
+  {
+    QString ogcOperatorName = UnaryOgcOperatorText[ i ];
+    if ( ogcOperatorName.isEmpty() )
+      continue;
+
+    if ( element.localName() == ogcOperatorName )
+    {
+      QgsExpression::Node *node = QgsExpression::NodeUnaryOperator::createFromOgcFilter( element, errorMessage );
+      if ( node )
+        return node;
+
+      return NULL;
+    }
+  }
+
+  // check for binary operators
+  int binaryOpCount = sizeof( BinaryOgcOperatorText ) / sizeof( BinaryOgcOperatorText[0] );
+  for ( int i = 0; i < binaryOpCount; i++ )
+  {
+    QString ogcOperatorName = BinaryOgcOperatorText[ i ];
+    if ( ogcOperatorName.isEmpty() )
+      continue;
+
+    if ( element.localName() == ogcOperatorName )
+    {
+      QgsExpression::Node *node = QgsExpression::NodeBinaryOperator::createFromOgcFilter( element, errorMessage );
+      if ( node )
+        return node;
+
+      return NULL;
+    }
+  }
+
+  // check for other OGC operators, convert them to expressions
+
+  if ( element.localName() == "PropertyIsNull" )
+  {
+    return QgsExpression::NodeBinaryOperator::createFromOgcFilter( element, errorMessage );
+  }
+  else if ( element.localName() == "Literal" )
+  {
+    return QgsExpression::NodeLiteral::createFromOgcFilter( element, errorMessage );
+  }
+  else if ( element.localName() == "Function")
+  {
+    return QgsExpression::NodeFunction::createFromOgcFilter( element, errorMessage );
+  }
+  else if ( element.localName() == "PropertyName")
+  {
+    return QgsExpression::NodeColumnRef::createFromOgcFilter( element, errorMessage );
+  }
+  else if ( element.localName() == "PropertyIsBetween" )
+  {
+    // <ogc:PropertyIsBetween> encode a Range check
+    QgsExpression::Node *operand = 0, *lowerBound = 0, *upperBound = 0;
+
+    QDomElement operandElem = element.firstChildElement( "LowerBoundary" );
+    if ( !operandElem.isNull() )
+      lowerBound = createFromOgcFilter( operandElem, errorMessage );
+
+    operandElem = element.firstChildElement( "UpperBoundary" );
+    if ( !operandElem.isNull() )
+      upperBound = createFromOgcFilter( operandElem, errorMessage );
+
+    // <ogc:expression>
+    operandElem = element.firstChildElement();
+    while ( !operandElem.isNull() )
+    {
+      if ( operandElem.localName() != "LowerBoundary" &&
+           operandElem.localName() != "UpperBoundary" )
+      {
+        operand = createFromOgcFilter( operandElem, errorMessage );
+        break;
+      }
+
+      operandElem = operandElem.nextSiblingElement();
+    }
+
+    if ( !operand || !lowerBound || !upperBound )
+    {
+      if ( operand )
+        delete operand;
+
+      if ( lowerBound )
+        delete lowerBound;
+
+      if ( upperBound )
+        delete upperBound;
+
+      errorMessage = "missing some required sub-elements in ogc:PropertyIsBetween";
+      return NULL;
+    }
+
+    QgsExpression::Node *geOperator = new QgsExpression::NodeBinaryOperator( boGE, operand, lowerBound );
+    QgsExpression::Node *leOperator = new QgsExpression::NodeBinaryOperator( boLE, operand, upperBound );
+    return new QgsExpression::NodeBinaryOperator( boAnd, geOperator, leOperator );
+  }
+
+  errorMessage += QString( "unable to convert '%1' element to a valid expression: it is not supported yet or it has invalid arguments" ).arg( element.tagName() );
+  return NULL;
+}
+
 ///////////////////////////////////////////////
 // nodes
 
@@ -567,6 +737,14 @@ QString QgsExpression::NodeList::dump() const
   return msg;
 }
 
+void QgsExpression::NodeList::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
+{
+  foreach( Node* n, mList )
+  {
+    n->toOgcFilter( doc, element );
+  }
+}
+
 //
 
 QVariant QgsExpression::NodeUnaryOperator::eval( QgsExpression* parent, QgsFeature* f )
@@ -607,6 +785,58 @@ QString QgsExpression::NodeUnaryOperator::dump() const
   return QString( "%1 %2" ).arg( UnaryOperatorText[mOp] ).arg( mOperand->dump() );
 }
 
+void QgsExpression::NodeUnaryOperator::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
+{
+  QDomElement uoElem;
+  switch ( mOp )
+  {
+    case uoMinus:
+      uoElem = doc.createElement( "ogc:Literal" );
+      uoElem.appendChild( doc.createTextNode( "-" ) );
+      break;
+    case uoNot:
+      uoElem = doc.createElement( "ogc:Not" );
+      break;
+
+    default:
+      element.appendChild( doc.createComment( QString( "Unary operator %1 not implemented yet" ).arg( UnaryOperatorText[mOp] ) ) );
+      return;
+  }
+  mOperand->toOgcFilter( doc, uoElem );
+  element.appendChild( uoElem );
+}
+
+QgsExpression::Node* QgsExpression::NodeUnaryOperator::createFromOgcFilter( QDomElement &element, QString &errorMessage )
+{
+  if ( element.isNull() )
+    return NULL;
+
+  int unaryOpCount = sizeof( UnaryOgcOperatorText ) / sizeof( UnaryOgcOperatorText[0] );
+  for ( int i = 0; i < unaryOpCount; i++ )
+  {
+    QString ogcOperatorName = UnaryOgcOperatorText[ i ];
+    if ( ogcOperatorName.isEmpty() )
+      continue;
+
+    if ( element.localName() != ogcOperatorName )
+      continue;
+
+    QDomElement operandElem = element.firstChildElement();
+    QgsExpression::Node* operand = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
+    if ( !operand )
+    {
+      if ( errorMessage.isEmpty() )
+       errorMessage = QString( "invalid operand for '%1' unary operator" ).arg( ogcOperatorName );
+      return NULL;
+    }
+
+    return new QgsExpression::NodeUnaryOperator( ( UnaryOperator ) i, operand );
+  }
+
+  errorMessage = QString( "%1 unary operator not supported." ).arg( element.tagName() );
+  return NULL;
+}
+
 //
 
 QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, QgsFeature* f )
@@ -822,6 +1052,171 @@ QString QgsExpression::NodeBinaryOperator::dump() const
   return QString( "%1 %2 %3" ).arg( mOpLeft->dump() ).arg( BinaryOperatorText[mOp] ).arg( mOpRight->dump() );
 }
 
+void QgsExpression::NodeBinaryOperator::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
+{
+  if ( mOp == boConcat )
+  {
+    // the concat binary operator must only convert its operands
+    mOpLeft->toOgcFilter( doc, element );
+    mOpRight->toOgcFilter( doc, element );
+    return;
+  }
+
+  if ( mOp == boIs || mOp == boIsNot )
+  {
+    // check if one of the operands is NULL
+    QgsExpression::NodeLiteral *opLeftLiteral = dynamic_cast<QgsExpression::NodeLiteral *>( mOpLeft );
+    QgsExpression::NodeLiteral *opRightLiteral = dynamic_cast<QgsExpression::NodeLiteral *>( mOpRight );
+
+    if ( opLeftLiteral && opLeftLiteral->value().isNull() &&
+         opRightLiteral && opRightLiteral->value().isNull() )
+    {
+      // why could anybody find useful to use NULL IS NULL???
+      // BTW avoid issues by converting it to 1 = 1
+      QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqual" );
+
+      QDomElement literalElem = doc.createElement( "ogc:Literal" );
+      literalElem.appendChild( doc.createTextNode( "1" ) );
+      eqElem.appendChild( literalElem );
+
+      literalElem = doc.createElement( "ogc:Literal" );
+      literalElem.appendChild( doc.createTextNode( "1" ) );
+      eqElem.appendChild( literalElem );
+
+      element.appendChild( eqElem );
+    }
+    else if ( ( opLeftLiteral && opLeftLiteral->value().isNull() ) ||
+              ( opRightLiteral && opRightLiteral->value().isNull() ) )
+    {
+      // at least one operand is NULL, use <ogc:PropertyIsNull> element
+      QDomElement isNullElem = doc.createElement( "ogc:PropertyIsNull" );
+      QgsExpression::Node *operand = opLeftLiteral->value().isNull() ? mOpRight : mOpLeft;
+      operand->toOgcFilter( doc, isNullElem );
+
+      if ( mOp == boIsNot )
+      {
+        // append to <ogc:Not> element if IS NOT operator was required
+        QDomElement notOpElem = doc.createElement( "ogc:Not" );
+        notOpElem.appendChild( isNullElem );
+        element.appendChild( notOpElem );
+      }
+      else
+      {
+        element.appendChild( isNullElem );
+      }
+    }
+    else
+    {
+      // both operands are not null, use <ogc:PropertyIsEqual> element
+      QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqual" );
+      mOpLeft->toOgcFilter( doc, eqElem );
+      mOpRight->toOgcFilter( doc, eqElem );
+      element.appendChild( eqElem );
+    }
+    return;
+  }
+
+  if ( mOp == boILike )
+  {
+    // XXX why ogc:PropertyIsLikeType extends ogc:ComparisonOpsType
+    // which has no matchCase attribute? Shouldn't it be better if
+    // would extend BinaryComparisonOpType which has that attribute
+    // and doesn't require to have a ogc:PropertyName as first parameter?
+    QgsExpression ilikeExpr( QString( "upper( %1 ) LIKE upper( %2 )" ).arg( mOpLeft->dump() ).arg( mOpRight->dump() ) );
+    ilikeExpr.toOgcFilter( doc, element );
+    return;
+  }
+
+  QString opText = BinaryOgcOperatorText[mOp];
+  if ( opText.isEmpty() )
+  {
+    // not implemented binary operators
+    // TODO: regex, % (mod), ^ (pow) are not supported yet
+    element.appendChild( doc.createComment( QString( "Binary operator %1 not implemented yet" ).arg( BinaryOperatorText[mOp] ) ) );
+    return;
+  }
+
+  QDomElement boElem = doc.createElement( "ogc:" + opText );
+  if ( mOp == boLike )
+  {
+    // setup wildcards to <ogc:PropertyIsLike>
+    boElem.setAttribute( "wildCard", "%" );
+    boElem.setAttribute( "singleChar", "?" );
+    boElem.setAttribute( "escapeChar", "!" );
+  }
+
+  mOpLeft->toOgcFilter( doc, boElem );
+  mOpRight->toOgcFilter( doc, boElem );
+  element.appendChild( boElem );
+}
+
+QgsExpression::Node* QgsExpression::NodeBinaryOperator::createFromOgcFilter( QDomElement &element, QString &errorMessage )
+{
+  if ( element.isNull() )
+    return NULL;
+
+  QgsExpression::Node* opLeft = 0;
+  QgsExpression::Node* opRight = 0;
+
+  // convert ogc:PropertyIsNull to IS operator with NULL right operand
+  if ( element.localName() == "PropertyIsNull" )
+  {
+    QDomElement operandElem = element.firstChildElement();
+    opLeft = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
+    if ( !opLeft )
+      return NULL;
+
+    opRight = new QgsExpression::NodeLiteral( QVariant() );
+    return new QgsExpression::NodeBinaryOperator( boIs, opLeft, opRight );
+  }
+
+  // the other binary operators
+  int binaryOpCount = sizeof( BinaryOgcOperatorText ) / sizeof( BinaryOgcOperatorText[0] );
+  for ( int i = 0; i < binaryOpCount; i++ )
+  {
+    QString ogcOperatorName = BinaryOgcOperatorText[ i ];
+    if ( ogcOperatorName.isEmpty() )
+      continue;
+
+    if ( element.localName() != ogcOperatorName )
+      continue;
+
+    QDomElement operandElem = element.firstChildElement();
+    opLeft = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
+    if ( !opLeft )
+    {
+      if ( errorMessage.isEmpty() )
+       errorMessage = QString( "invalid left operand for '%1' binary operator" ).arg( ogcOperatorName );
+      break;
+    }
+
+    operandElem = operandElem.nextSiblingElement();
+    opRight = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
+    if ( !opRight )
+    {
+      if ( errorMessage.isEmpty() )
+       errorMessage = QString( "invalid right operand for '%1' binary operator" ).arg( ogcOperatorName );
+      break;
+    }
+
+    return new QgsExpression::NodeBinaryOperator( ( BinaryOperator ) i, opLeft, opRight );
+  }
+
+  if ( !opLeft && !opRight )
+  {
+    errorMessage = QString( "'%1' binary operator not supported." ).arg( element.tagName() );
+    return NULL;
+  }
+
+  if ( opLeft )
+    delete opLeft;
+
+  if ( opRight )
+    delete opRight;
+
+  return NULL;
+}
+
 //
 
 QVariant QgsExpression::NodeInOperator::eval( QgsExpression* parent, QgsFeature* f )
@@ -885,6 +1280,31 @@ QString QgsExpression::NodeInOperator::dump() const
   return QString( "%1 IN (%2)" ).arg( mNode->dump() ).arg( mList->dump() );
 }
 
+void QgsExpression::NodeInOperator::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
+{
+  // XXX use a function instead of multiple comparations?
+
+  QDomElement *parent = &element;
+
+  QDomElement orElem;
+  if ( mList->list().size() > 1 )
+  {
+    orElem = doc.createElement( "ogc:Or" );
+    element.appendChild( orElem );
+
+    parent = &orElem;
+  }
+
+  foreach( Node* n, mList->list() )
+  {
+    QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqualTo" );
+    mNode->toOgcFilter( doc, eqElem );
+    n->toOgcFilter( doc, eqElem );
+
+    parent->appendChild( eqElem );
+  }
+}
+
 //
 
 QVariant QgsExpression::NodeFunction::eval( QgsExpression* parent, QgsFeature* f )
@@ -935,6 +1355,58 @@ QString QgsExpression::NodeFunction::dump() const
     return QString( "%1(%2)" ).arg( fd.mName ).arg( mArgs ? mArgs->dump() : QString() ); // function
 }
 
+void QgsExpression::NodeFunction::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
+{
+  const FunctionDef& fd = BuiltinFunctions()[mFnIndex];
+  if ( fd.mParams == 0 )
+    return; // TODO: special column
+
+  QDomElement funcElem = doc.createElement( "ogc:Function" );
+  funcElem.setAttribute( "name", fd.mName );
+  mArgs->toOgcFilter( doc, funcElem );
+  element.appendChild( funcElem );
+}
+
+QgsExpression::Node* QgsExpression::NodeFunction::createFromOgcFilter( QDomElement &element, QString &errorMessage )
+{
+  if ( element.isNull() )
+    return NULL;
+
+  if ( element.localName() != "Function" )
+  {
+    errorMessage = QString( "ogc:Function expected, got %1" ).arg( element.tagName() );
+    return NULL;
+  }
+
+  for ( int i = 0; i < BuiltinFunctions().size(); i++ )
+  {
+    QgsExpression::FunctionDef funcDef = BuiltinFunctions()[i];
+
+    if ( element.attribute( "name" ) != funcDef.mName )
+      continue;
+
+    QgsExpression::NodeList *args = new QgsExpression::NodeList();
+
+    QDomElement operandElem = element.firstChildElement();
+    while ( !operandElem.isNull() )
+    {
+      QgsExpression::Node* op = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
+      if ( !op )
+      {
+        delete args;
+        return NULL;
+      }
+      args->append( op );
+
+      operandElem = operandElem.nextSiblingElement();
+    }
+
+    return new QgsExpression::NodeFunction( i, args );
+  }
+
+  return NULL;
+}
+
 //
 
 QVariant QgsExpression::NodeLiteral::eval( QgsExpression* , QgsFeature* )
@@ -962,6 +1434,92 @@ QString QgsExpression::NodeLiteral::dump() const
   }
 }
 
+void QgsExpression::NodeLiteral::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
+{
+  QString value;
+  if ( !mValue.isNull() )
+  {
+    switch ( mValue.type() )
+    {
+      case QVariant::Int:
+        value = QString::number( mValue.toInt() );
+        break;
+      case QVariant::Double:
+        value = QString::number( mValue.toDouble() );
+        break;
+      case QVariant::String:
+        value = mValue.toString();
+        break;
+      default:
+        break;
+    }
+  }
+  QDomElement litElem = doc.createElement( "ogc:Literal" );
+  litElem.appendChild( doc.createTextNode( value ) );
+  element.appendChild( litElem );
+}
+
+QgsExpression::Node* QgsExpression::NodeLiteral::createFromOgcFilter( QDomElement &element, QString &errorMessage )
+{
+  if ( element.isNull() )
+    return NULL;
+
+  if ( element.localName() != "Literal" )
+  {
+    errorMessage = QString( "ogc:Literal expected, got %1" ).arg( element.tagName() );
+    return NULL;
+  }
+
+  QgsExpression::Node *root = 0;
+
+  // the literal content can have more children (e.g. CDATA section, text, ...)
+  QDomNode childNode = element.firstChild();
+  while ( !childNode.isNull() )
+  {
+    QgsExpression::Node* operand = 0;
+
+    if ( childNode.nodeType() == QDomNode::ElementNode )
+    {
+      // found a element node (e.g. PropertyName), convert it
+      QDomElement operandElem = childNode.toElement();
+      operand = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage );
+      if ( !operand )
+      {
+        if ( root )
+          delete root;
+
+        errorMessage = QString( "'%1' is an invalid or not supported content for ogc:Literal" ).arg( operandElem.tagName() );
+        return NULL;
+      }
+    }
+    else
+    {
+      // probably a text/CDATA node, convert its content to string
+      operand = new QgsExpression::NodeLiteral( childNode.nodeValue() );
+    }
+
+    if ( !operand )
+      continue;
+
+    // use the concat operator to merge the ogc:Literal children
+    if ( !root )
+    {
+      root = operand;
+    }
+    else
+    {
+      root = new QgsExpression::NodeBinaryOperator( boConcat, root, operand );
+    }
+
+    childNode = childNode.nextSibling();
+  }
+
+  if ( root )
+    return root;
+
+  return NULL;
+}
+
 //
 
 QVariant QgsExpression::NodeColumnRef::eval( QgsExpression* /*parent*/, QgsFeature* f )
@@ -989,6 +1547,27 @@ QString QgsExpression::NodeColumnRef::dump() const
   return mName;
 }
 
+void QgsExpression::NodeColumnRef::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
+{
+  QDomElement propElem = doc.createElement( "ogc:PropertyName" );
+  propElem.appendChild( doc.createTextNode( mName ) );
+  element.appendChild( propElem );
+}
+
+QgsExpression::Node* QgsExpression::NodeColumnRef::createFromOgcFilter( QDomElement &element, QString &errorMessage )
+{
+  if ( element.isNull() )
+    return NULL;
+
+  if ( element.localName() != "PropertyName" )
+  {
+    errorMessage = QString( "ogc:PropertyName expected, got %1" ).arg( element.tagName() );
+    return NULL;
+  }
+
+  return new QgsExpression::NodeColumnRef( element.firstChild().nodeValue() );
+}
+
 //
 
 QVariant QgsExpression::NodeCondition::eval( QgsExpression* parent, QgsFeature* f )
@@ -1045,6 +1624,12 @@ QString QgsExpression::NodeCondition::dump() const
   return msg;
 }
 
+void QgsExpression::NodeCondition::toOgcFilter( QDomDocument &doc, QDomElement &element ) const
+{
+  // TODO: if(cond) ... [else if (cond2) ...]* [else ...]
+  element.appendChild( doc.createComment( "CASE operator not implemented yet" ) );
+}
+
 QStringList QgsExpression::NodeCondition::referencedColumns() const
 {
   QStringList lst;
diff --git a/src/core/qgsexpression.h b/src/core/qgsexpression.h
index 4f64f82..617ae6d 100644
--- a/src/core/qgsexpression.h
+++ b/src/core/qgsexpression.h
@@ -170,6 +170,8 @@ class CORE_EXPORT QgsExpression
     static const char* BinaryOperatorText[];
     static const char* UnaryOperatorText[];
 
+    static const char* BinaryOgcOperatorText[];
+    static const char* UnaryOgcOperatorText[];
 
     typedef QVariant( *FcnEval )( const QVariantList& values, QgsFeature* f, QgsExpression* parent );
 
@@ -226,6 +228,9 @@ class CORE_EXPORT QgsExpression
 
         virtual QString dump() const = 0;
 
+        virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const { Q_UNUSED( doc ); Q_UNUSED( element ); }
+        static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );
+
         virtual QStringList referencedColumns() const = 0;
         virtual bool needsGeometry() const = 0;
 
@@ -243,6 +248,8 @@ class CORE_EXPORT QgsExpression
         QList<Node*> list() { return mList; }
 
         virtual QString dump() const;
+        virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
+
       protected:
         QList<Node*> mList;
     };
@@ -259,6 +266,10 @@ class CORE_EXPORT QgsExpression
         virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
         virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
         virtual QString dump() const;
+
+        virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
+        static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );
+
         virtual QStringList referencedColumns() const { return mOperand->referencedColumns(); }
         virtual bool needsGeometry() const { return mOperand->needsGeometry(); }
         virtual void accept( Visitor& v ) { v.visit( this ); }
@@ -281,6 +292,10 @@ class CORE_EXPORT QgsExpression
         virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
         virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
         virtual QString dump() const;
+
+        virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
+        static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );
+
         virtual QStringList referencedColumns() const { return mOpLeft->referencedColumns() + mOpRight->referencedColumns(); }
         virtual bool needsGeometry() const { return mOpLeft->needsGeometry() || mOpRight->needsGeometry(); }
         virtual void accept( Visitor& v ) { v.visit( this ); }
@@ -308,6 +323,9 @@ class CORE_EXPORT QgsExpression
         virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
         virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
         virtual QString dump() const;
+
+        virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
+
         virtual QStringList referencedColumns() const { QStringList lst( mNode->referencedColumns() ); foreach( Node* n, mList->list() ) lst.append( n->referencedColumns() ); return lst; }
         virtual bool needsGeometry() const { bool needs = false; foreach( Node* n, mList->list() ) needs |= n->needsGeometry(); return needs; }
         virtual void accept( Visitor& v ) { v.visit( this ); }
@@ -331,6 +349,10 @@ class CORE_EXPORT QgsExpression
         virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
         virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
         virtual QString dump() const;
+
+        virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
+        static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );
+
         virtual QStringList referencedColumns() const { QStringList lst; if ( !mArgs ) return lst; foreach( Node* n, mArgs->list() ) lst.append( n->referencedColumns() ); return lst; }
         virtual bool needsGeometry() const { bool needs = BuiltinFunctions()[mFnIndex].mUsesGeometry; if ( mArgs ) { foreach( Node* n, mArgs->list() ) needs |= n->needsGeometry(); } return needs; }
         virtual void accept( Visitor& v ) { v.visit( this ); }
@@ -351,6 +373,10 @@ class CORE_EXPORT QgsExpression
         virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
         virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
         virtual QString dump() const;
+
+        virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
+        static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );
+
         virtual QStringList referencedColumns() const { return QStringList(); }
         virtual bool needsGeometry() const { return false; }
         virtual void accept( Visitor& v ) { v.visit( this ); }
@@ -369,6 +395,10 @@ class CORE_EXPORT QgsExpression
         virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
         virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
         virtual QString dump() const;
+
+        virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
+        static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );
+
         virtual QStringList referencedColumns() const { return QStringList( mName ); }
         virtual bool needsGeometry() const { return false; }
         virtual void accept( Visitor& v ) { v.visit( this ); }
@@ -399,6 +429,9 @@ class CORE_EXPORT QgsExpression
         virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
         virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
         virtual QString dump() const;
+
+        virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
+
         virtual QStringList referencedColumns() const;
         virtual bool needsGeometry() const;
         virtual void accept( Visitor& v ) { v.visit( this ); }
@@ -428,7 +461,13 @@ class CORE_EXPORT QgsExpression
     /** entry function for the visitor pattern */
     void acceptVisitor( Visitor& v );
 
+    // convert from/to OGC Filter
+    void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
+    static QgsExpression* createFromOgcFilter( QDomElement &element );
+
   protected:
+    // internally used to create an empty expression
+    QgsExpression() : mRootNode( NULL ), mRowNumber( 0 ), mCalc( NULL ) {}
 
     QString mExpression;
     Node* mRootNode;
diff --git a/src/core/qgsmaplayer.cpp b/src/core/qgsmaplayer.cpp
index dbe7f23..3db1cea 100644
--- a/src/core/qgsmaplayer.cpp
+++ b/src/core/qgsmaplayer.cpp
@@ -857,7 +857,146 @@ QString QgsMapLayer::saveNamedStyle( const QString theURI, bool & theResultFlag
   return myErrorMessage;
 }
 
+QString QgsMapLayer::saveSldStyle( const QString theURI, bool & theResultFlag )
+{
+  QDomDocument myDocument = QDomDocument();
+
+  QDomNode header = myDocument.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
+  myDocument.appendChild( header );
+
+  // Create the root element
+  QDomElement root = myDocument.createElementNS( "http://www.opengis.net/sld", "StyledLayerDescriptor" );
+  root.setAttribute( "version", "1.1.0" );
+  root.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" );
+  root.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
+  root.setAttribute( "xmlns:se", "http://www.opengis.net/se" );
+  root.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
+  root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
+  myDocument.appendChild( root );
+
+  // Create the NamedLayer element
+  QDomElement namedLayerNode = myDocument.createElement( "NamedLayer" );
+  root.appendChild( namedLayerNode );
+
+  QString errorMsg;
+  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
+  if ( !vlayer )
+  {
+    theResultFlag = false;
+    return tr( "Could not save symbology because:\n%1" ).arg( "Non-vector layers not supported yet" );
+  }
+
+  if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg ) )
+  {
+    theResultFlag = false;
+    return tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
+  }
+
+  // check if the uri is a file or ends with .sld,
+  // which indicates that it should become one
+  QString filename;
+  if ( vlayer->providerType() == "ogr" )
+  {
+    QStringList theURIParts = theURI.split( "|" );
+    filename = theURIParts[0];
+  }
+  else if ( vlayer->providerType() == "delimitedtext" )
+  {
+    filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile();
+  }
+  else
+  {
+    filename = theURI;
+  }
+
+  QFileInfo myFileInfo( filename );
+  if ( myFileInfo.exists() || filename.endsWith( ".sld", Qt::CaseInsensitive ) )
+  {
+    QFileInfo myDirInfo( myFileInfo.path() );  //excludes file name
+    if ( !myDirInfo.isWritable() )
+    {
+      return tr( "The directory containing your dataset needs to be writable!" );
+    }
+
+    // now construct the file name for our .sld style file
+    QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";
+
+    QFile myFile( myFileName );
+    if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
+    {
+      QTextStream myFileStream( &myFile );
+      // save as utf-8 with 2 spaces for indents
+      myDocument.save( myFileStream, 2 );
+      myFile.close();
+      theResultFlag = true;
+      return tr( "Created default style file as %1" ).arg( myFileName );
+    }
+  }
 
+  theResultFlag = false;
+  return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
+}
+
+QString QgsMapLayer::loadSldStyle( const QString theURI, bool &theResultFlag )
+{
+  QgsDebugMsg( "Entered." );
+
+  theResultFlag = false;
+
+  QDomDocument myDocument;
+
+  // location of problem associated with errorMsg
+  int line, column;
+  QString myErrorMessage;
+
+  QFile myFile( theURI );
+  if ( myFile.open( QFile::ReadOnly ) )
+  {
+    // read file
+    theResultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
+    if ( !theResultFlag )
+      myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
+    myFile.close();
+  }
+  else
+  {
+    myErrorMessage = tr( "Unable to open file %1" ).arg( theURI );
+  }
+
+  if ( !theResultFlag )
+  {
+    return myErrorMessage;
+  }
+
+  // check for root SLD element
+  QDomElement myRoot = myDocument.firstChildElement( "StyledLayerDescriptor" );
+  if ( myRoot.isNull() )
+  {
+    myErrorMessage = QString( "Error: StyledLayerDescriptor element not found in %1" ).arg( theURI );
+    theResultFlag = false;
+    return myErrorMessage;
+  }
+
+  // now get the style node out and pass it over to the layer
+  // to deserialise...
+  QDomElement namedLayerElem = myRoot.firstChildElement( "NamedLayer" );
+  if ( namedLayerElem.isNull() )
+  {
+    myErrorMessage = QString( "Info: NamedLayer element not found." );
+    theResultFlag = false;
+    return myErrorMessage;
+  }
+
+  QString errorMsg;
+  theResultFlag = readSld( namedLayerElem, errorMsg );
+  if ( !theResultFlag )
+  {
+    myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg );
+    return myErrorMessage;
+  }
+
+  return "";
+}
 
 
 QUndoStack* QgsMapLayer::undoStack()
diff --git a/src/core/qgsmaplayer.h b/src/core/qgsmaplayer.h
index 76f964c..eb16455 100644
--- a/src/core/qgsmaplayer.h
+++ b/src/core/qgsmaplayer.h
@@ -289,6 +289,13 @@ class CORE_EXPORT QgsMapLayer : public QObject
      */
     virtual QString saveNamedStyle( const QString theURI, bool & theResultFlag );
 
+    virtual QString saveSldStyle( const QString theURI, bool & theResultFlag );
+    virtual QString loadSldStyle( const QString theURI, bool &theResultFlag );
+
+    virtual bool readSld( const QDomNode& node, QString& errorMessage )
+    { Q_UNUSED( node ); errorMessage = QString( "Layer type %1 not supported" ).arg( type() ); return false; }
+
+
     /** Read the symbology for the current layer from the Dom node supplied.
      * @param node node that will contain the symbology definition for this layer.
      * @param errorMessage reference to string that will be updated with any error messages
diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp
index cc8a6d8..2c91091 100644
--- a/src/core/qgsvectorlayer.cpp
+++ b/src/core/qgsvectorlayer.cpp
@@ -3393,6 +3393,53 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
   return true;
 }
 
+bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage )
+{
+  // get the Name element
+  QDomElement nameElem = node.firstChildElement( "Name" );
+  if ( nameElem.isNull() )
+  {
+    errorMessage = "Warning: Name element not found within NamedLayer while it's required.";
+  }
+
+  if ( hasGeometryType() )
+  {
+    setUsingRendererV2( true );
+
+    QgsFeatureRendererV2* r = QgsFeatureRendererV2::loadSld( node, geometryType(), errorMessage );
+    if ( !r )
+      return false;
+
+    setRendererV2( r );
+  }
+  return true;
+}
+
+
+bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
+{
+  Q_UNUSED( errorMessage );
+
+  // store the Name element
+  QDomElement nameNode = doc.createElement( "se:Name" );
+  nameNode.appendChild( doc.createTextNode( name() ) );
+  node.appendChild( nameNode );
+
+  if ( hasGeometryType() )
+  {
+    if ( mUsingRendererV2 )
+    {
+      node.appendChild( mRendererV2->writeSld( doc, *this ) );
+    }
+    else
+    {
+      node.appendChild( doc.createComment( "Old Renderer not supported yet" ) );
+      return false;
+    }
+  }
+  return true;
+}
+
 
 bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry* geom )
 {
diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h
index eca5cff..a06c59e 100644
--- a/src/core/qgsvectorlayer.h
+++ b/src/core/qgsvectorlayer.h
@@ -292,6 +292,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
      */
     bool writeSymbology( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const;
 
+    bool writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const;
+    bool readSld( const QDomNode& node, QString& errorMessage );
 
     /**
      * Number of features in the layer. This is necessary if features are
diff --git a/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp b/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
index c355cc0..ea9d014 100644
--- a/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
+++ b/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
@@ -68,6 +68,37 @@ QString QgsRendererCategoryV2::dump()
   return QString( "%1::%2::%3\n" ).arg( mValue.toString() ).arg( mLabel ).arg( mSymbol->dump() );
 }
 
+void QgsRendererCategoryV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  if ( !mSymbol || props.value( "attribute", "" ).isEmpty() )
+    return;
+
+  QDomElement ruleElem = doc.createElement( "se:Rule" );
+  element.appendChild( ruleElem );
+
+  QString valueStr = QString( "value: %1" ).arg( mValue.toString() );
+
+  QDomElement nameElem = doc.createElement( "se:Name" );
+  nameElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : valueStr ) );
+  ruleElem.appendChild( nameElem );
+
+  QString descrName = props.value( "version", "1.1" ) < "1.1" ? "Abstract" : "se:Description";
+  QString descrValue = QString( "Categorized symbol rendererV2 - %1" ).arg( valueStr );
+
+  QDomElement descrElem = doc.createElement( descrName );
+  descrElem.appendChild( doc.createTextNode( descrValue ) );
+  ruleElem.appendChild( descrElem );
+
+  // create the ogc:Filter for the range
+  QDomElement filterElem = doc.createElement( "ogc:Filter" );
+
+  QString filterFunc = QString( "%1 = '%2'" )
+      .arg( props[ "attribute" ] ).arg( mValue.toString().replace( "'", "''" ) );
+  QgsSymbolLayerV2Utils::createFunctionElement( doc, filterElem, filterFunc );
+
+  mSymbol->toSld( doc, ruleElem, props );
+}
+
 ///////////////////
 
 QgsCategorizedSymbolRendererV2::QgsCategorizedSymbolRendererV2( QString attrName, QgsCategoryList categories )
@@ -331,6 +362,23 @@ QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::clone()
   return r;
 }
 
+void QgsCategorizedSymbolRendererV2::toSld( QDomDocument &doc, QDomElement &element ) const
+{
+  QgsStringMap props;
+  props[ "attribute" ] = mAttrName;
+  if ( !mRotationField.isEmpty() )
+    props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
+  if ( !mSizeScaleField.isEmpty() )
+    props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );
+
+  // create a Rule for each range
+  for ( QgsCategoryList::const_iterator it = mCategories.constBegin(); it != mCategories.constEnd(); it++ )
+  {
+    QgsStringMap catProps( props );
+    it->toSld( doc, element, catProps );
+  }
+}
+
 QgsSymbolV2List QgsCategorizedSymbolRendererV2::symbols()
 {
   QgsSymbolV2List lst;
diff --git a/src/core/symbology-ng/qgscategorizedsymbolrendererv2.h b/src/core/symbology-ng/qgscategorizedsymbolrendererv2.h
index d9068ed..706be9a 100644
--- a/src/core/symbology-ng/qgscategorizedsymbolrendererv2.h
+++ b/src/core/symbology-ng/qgscategorizedsymbolrendererv2.h
@@ -1,6 +1,7 @@
 #ifndef QGSCATEGORIZEDSYMBOLRENDERERV2_H
 #define QGSCATEGORIZEDSYMBOLRENDERERV2_H
 
+#include "qgssymbolv2.h"
 #include "qgsrendererv2.h"
 
 #include <QHash>
@@ -32,6 +33,8 @@ class CORE_EXPORT QgsRendererCategoryV2
     // debugging
     QString dump();
 
+    void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;
+
   protected:
     QVariant mValue;
     QgsSymbolV2* mSymbol;
@@ -60,6 +63,8 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2
 
     virtual QgsFeatureRendererV2* clone();
 
+    virtual void toSld( QDomDocument& doc, QDomElement &element ) const;
+
     //! returns bitwise OR-ed capabilities of the renderer
     //! \note added in 2.0
     virtual int capabilities() { return SymbolLevels | RotationField; }
diff --git a/src/core/symbology-ng/qgsellipsesymbollayerv2.cpp b/src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
index 8f7c515..ef029bf 100644
--- a/src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
+++ b/src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
@@ -2,8 +2,12 @@
 #include "qgsfeature.h"
 #include "qgsrendercontext.h"
 #include "qgsvectorlayer.h"
+#include "qgslogger.h"
+
 #include <QPainter>
 #include <QSet>
+#include <QDomDocument>
+#include <QDomElement>
 
 QgsEllipseSymbolLayerV2::QgsEllipseSymbolLayerV2(): mSymbolName( "circle" ), mSymbolWidth( 4 ), mSymbolHeight( 3 ),
     mFillColor( Qt::black ), mOutlineColor( Qt::white ), mOutlineWidth( 0 )
@@ -187,6 +191,115 @@ QgsSymbolLayerV2* QgsEllipseSymbolLayerV2::clone() const
   return QgsEllipseSymbolLayerV2::create( properties() );
 }
 
+void QgsEllipseSymbolLayerV2::toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
+  if ( !props.value( "uom", "" ).isEmpty() )
+    symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
+  element.appendChild( symbolizerElem );
+
+  // <Geometry>
+  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
+
+  writeSldMarker( doc, symbolizerElem, props );
+}
+
+void QgsEllipseSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  // <Graphic>
+  QDomElement graphicElem = doc.createElement( "se:Graphic" );
+  element.appendChild( graphicElem );
+
+  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mFillColor, mOutlineColor, mOutlineWidth, mSymbolWidth );
+
+  // store w/h factor in a <VendorOption>
+  double widthHeightFactor = mSymbolWidth / mSymbolHeight;
+  QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
+  graphicElem.appendChild( factorElem );
+
+  // <Rotation>
+  QString angleFunc = props.value( "angle", "" );
+  if ( angleFunc.isEmpty() )  // symbol has no angle set
+  {
+    if ( !mRotationField.isEmpty() )
+      angleFunc = mRotationField;
+    else if ( !doubleNear( mAngle, 0.0 ) )
+      angleFunc = QString::number( mAngle );
+  }
+  else if ( !mRotationField.isEmpty() )
+  {
+    // the symbol has an angle and the symbol layer have a rotation
+    // property set
+    angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mRotationField );
+  }
+  else if ( !doubleNear( mAngle, 0.0 ) )
+  {
+    // both the symbol and the symbol layer have angle value set
+    bool ok;
+    double angle = angleFunc.toDouble( &ok );
+    if ( !ok )
+    {
+      // its a string (probably a property name or a function)
+      angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
+    }
+    else if ( !doubleNear( angle + mAngle, 0.0 ) )
+    {
+      // it's a double value
+      angleFunc = QString::number( angle + mAngle );
+    }
+  }
+  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
+}
+
+QgsSymbolLayerV2* QgsEllipseSymbolLayerV2::createFromSld( QDomElement &element )
+{
+  QgsDebugMsg( "Entered." );
+
+  QDomElement graphicElem = element.firstChildElement( "Graphic" );
+  if( graphicElem.isNull() )
+    return NULL;
+
+  QString name = "circle";
+  QColor color, borderColor;
+  double borderWidth, size;
+  double widthHeightFactor = 1.0;
+
+  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
+  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
+  {
+    if ( it.key() == "widthHeightFactor" )
+    {
+      bool ok;
+      double v = it.value().toDouble( &ok );
+      if ( ok && !doubleNear( v, 0.0 ) && v > 0 )
+        widthHeightFactor = v;
+    }
+  }
+
+  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderWidth, size ) )
+    return NULL;
+
+  double angle = 0.0;
+  QString angleFunc;
+  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
+  {
+    bool ok;
+    double d = angleFunc.toDouble( &ok );
+    if ( ok )
+      angle = d;
+  }
+
+  QgsEllipseSymbolLayerV2 *m = new QgsEllipseSymbolLayerV2();
+  m->setSymbolName( name );
+  m->setColor( color );
+  m->setOutlineColor( borderColor );
+  m->setOutlineWidth( borderWidth );
+  m->setSymbolWidth( size );
+  m->setSymbolHeight( size / widthHeightFactor );
+  m->setAngle( angle );
+  return m;
+}
+
 QgsStringMap QgsEllipseSymbolLayerV2::properties() const
 {
   QgsStringMap map;
diff --git a/src/core/symbology-ng/qgsellipsesymbollayerv2.h b/src/core/symbology-ng/qgsellipsesymbollayerv2.h
index c234e3b..8552f0b 100644
--- a/src/core/symbology-ng/qgsellipsesymbollayerv2.h
+++ b/src/core/symbology-ng/qgsellipsesymbollayerv2.h
@@ -12,6 +12,7 @@ class CORE_EXPORT QgsEllipseSymbolLayerV2: public QgsMarkerSymbolLayerV2
     ~QgsEllipseSymbolLayerV2();
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     void renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context );
     QString layerType() const;
@@ -20,6 +21,9 @@ class CORE_EXPORT QgsEllipseSymbolLayerV2: public QgsMarkerSymbolLayerV2
     QgsSymbolLayerV2* clone() const;
     QgsStringMap properties() const;
 
+    void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;
+    void writeSldMarker( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;
+
     void setSymbolName( const QString& name ) { mSymbolName = name; }
     QString symbolName() const { return mSymbolName; }
 
diff --git a/src/core/symbology-ng/qgsfillsymbollayerv2.cpp b/src/core/symbology-ng/qgsfillsymbollayerv2.cpp
index df309fc..a85816d 100644
--- a/src/core/symbology-ng/qgsfillsymbollayerv2.cpp
+++ b/src/core/symbology-ng/qgsfillsymbollayerv2.cpp
@@ -5,10 +5,13 @@
 #include "qgsrendercontext.h"
 #include "qgsproject.h"
 #include "qgssvgcache.h"
+#include "qgslogger.h"
 
 #include <QPainter>
 #include <QFile>
 #include <QSvgRenderer>
+#include <QDomDocument>
+#include <QDomElement>
 
 QgsSimpleFillSymbolLayerV2::QgsSimpleFillSymbolLayerV2( QColor color, Qt::BrushStyle style, QColor borderColor, Qt::PenStyle borderStyle, double borderWidth )
     : mBrushStyle( style ), mBorderColor( borderColor ), mBorderStyle( borderStyle ), mBorderWidth( borderWidth )
@@ -117,6 +120,63 @@ QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::clone() const
   return sl;
 }
 
+void QgsSimpleFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  if ( mBrushStyle == Qt::NoBrush && mBorderStyle == Qt::NoPen )
+    return;
+
+  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
+  if ( !props.value( "uom", "" ).isEmpty() )
+    symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
+  element.appendChild( symbolizerElem );
+
+  // <Geometry>
+  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
+
+  if ( mBrushStyle != Qt::NoBrush )
+  {
+    // <Fill>
+    QDomElement fillElem = doc.createElement( "se:Fill" );
+    symbolizerElem.appendChild( fillElem );
+    QgsSymbolLayerV2Utils::fillToSld( doc, fillElem, mBrushStyle, mColor );
+  }
+
+  if ( mBorderStyle != Qt::NoPen )
+  {
+    // <Stroke>
+    QDomElement strokeElem = doc.createElement( "se:Stroke" );
+    symbolizerElem.appendChild( strokeElem );
+    QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, mBorderStyle, mBorderColor, mBorderWidth );
+  }
+
+  // <se:Displacement>
+  QgsSymbolLayerV2Utils::createDisplacementElement( doc, symbolizerElem, mOffset );
+}
+
+QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::createFromSld( QDomElement &element )
+{
+  QgsDebugMsg( "Entered." );
+
+  QColor color, borderColor;
+  Qt::BrushStyle fillStyle;
+  Qt::PenStyle borderStyle;
+  double borderWidth;
+
+  QDomElement fillElem = element.firstChildElement( "Fill" );
+  QgsSymbolLayerV2Utils::fillFromSld( fillElem, fillStyle, color );
+
+  QDomElement strokeElem = element.firstChildElement( "Stroke" );
+  QgsSymbolLayerV2Utils::lineFromSld( strokeElem, borderStyle, borderColor, borderWidth );
+
+  QPointF offset;
+  QgsSymbolLayerV2Utils::displacementFromSldElement( element, offset );
+
+  QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, fillStyle, borderColor, borderStyle, borderWidth );
+  sl->setOffset( offset );
+  return sl;
+}
+
+
 //QgsImageFillSymbolLayer
 
 QgsImageFillSymbolLayer::QgsImageFillSymbolLayer(): mOutlineWidth( 0.0 ), mOutline( 0 )
@@ -380,6 +440,123 @@ QgsSymbolLayerV2* QgsSVGFillSymbolLayer::clone() const
   return clonedLayer;
 }
 
+void QgsSVGFillSymbolLayer::toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
+  if ( !props.value( "uom", "" ).isEmpty() )
+    symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
+  element.appendChild( symbolizerElem );
+
+  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
+
+  QDomElement fillElem = doc.createElement( "se:Fill" );
+  symbolizerElem.appendChild( fillElem );
+
+  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
+  fillElem.appendChild( graphicFillElem );
+
+  QDomElement graphicElem = doc.createElement( "se:Graphic" );
+  graphicFillElem.appendChild( graphicElem );
+
+  if ( !mSvgFilePath.isEmpty() )
+  {
+    QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mSvgFillColor, mPatternWidth );
+  }
+  else
+  {
+    // TODO: create svg from data
+    // <se:InlineContent>
+    symbolizerElem.appendChild( doc.createComment( "SVG from data not implemented yet" ) );
+  }
+
+  if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
+  {
+    QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, mSvgOutlineWidth );
+  }
+
+  // <Rotation>
+  QString angleFunc;
+  bool ok;
+  double angle = props.value( "angle", "0" ).toDouble( &ok );
+  if ( !ok )
+  {
+    angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
+  }
+  else if ( angle + mAngle != 0 )
+  {
+    angleFunc = QString::number( angle + mAngle );
+  }
+  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
+
+  if ( mOutline )
+  {
+    // the outline sub symbol should be stored within the Stroke element,
+    // but it will be stored in a separated LineSymbolizer because it could
+    // have more than one layer
+    mOutline->toSld( doc, element, props );
+  }
+}
+
+QgsSymbolLayerV2* QgsSVGFillSymbolLayer::createFromSld( QDomElement &element )
+{
+  QgsDebugMsg( "Entered." );
+
+  QString path, mimeType;
+  QColor fillColor, borderColor;
+  Qt::PenStyle penStyle;
+  double size, borderWidth;
+
+  QDomElement fillElem = element.firstChildElement( "Fill" );
+  if( fillElem.isNull() )
+    return NULL;
+
+  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
+  if( graphicFillElem.isNull() )
+    return NULL;
+
+  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
+  if( graphicElem.isNull() )
+    return NULL;
+
+  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
+    return NULL;
+
+  if ( mimeType != "image/svg+xml" )
+    return NULL;
+
+  QgsSymbolLayerV2Utils::lineFromSld( graphicElem, penStyle, borderColor, borderWidth );
+
+  double angle = 0.0;
+  QString angleFunc;
+  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
+  {
+    bool ok;
+    double d = angleFunc.toDouble( &ok );
+    if ( ok )
+      angle = d;
+  }
+
+  QgsSVGFillSymbolLayer* sl = new QgsSVGFillSymbolLayer( path, size, angle );
+  sl->setSvgFillColor( fillColor );
+  sl->setSvgOutlineColor( borderColor );
+  sl->setSvgOutlineWidth( borderWidth );
+
+  // try to get the outline
+  QDomElement strokeElem = element.firstChildElement( "Stroke" );
+  if ( !strokeElem.isNull() )
+  {
+    QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createLineLayerFromSld( strokeElem );
+    if ( l )
+    {
+      QgsSymbolLayerV2List layers;
+      layers.append( l );
+      sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
+    }
+  }
+
+  return sl;
+}
+
 void QgsSVGFillSymbolLayer::storeViewBox()
 {
   if ( !mSvgData.isEmpty() )
@@ -630,6 +807,52 @@ QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::clone() const
   return clonedLayer;
 }
 
+void QgsLinePatternFillSymbolLayer::toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
+  if ( !props.value( "uom", "" ).isEmpty() )
+    symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
+  element.appendChild( symbolizerElem );
+
+  // <Geometry>
+  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
+
+  QDomElement fillElem = doc.createElement( "se:Fill" );
+  symbolizerElem.appendChild( fillElem );
+
+  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
+  fillElem.appendChild( graphicFillElem );
+
+  QDomElement graphicElem = doc.createElement( "se:Graphic" );
+  graphicFillElem.appendChild( graphicElem );
+
+  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), mColor, mLineWidth, mDistance );
+
+  // <Rotation>
+  QString angleFunc;
+  bool ok;
+  double angle = props.value( "angle", "0" ).toDouble( &ok );
+  if ( !ok )
+  {
+    angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mLineAngle );
+  }
+  else if ( angle + mLineAngle != 0 )
+  {
+    angleFunc = QString::number( angle + mLineAngle );
+  }
+  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
+
+  // <se:Displacement>
+  QPointF lineOffset( qSin( mLineAngle ) * mOffset, qCos( mLineAngle ) * mOffset );
+  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, lineOffset );
+}
+
+QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::createFromSld( QDomElement &element )
+{
+  Q_UNUSED( element );
+  return NULL;
+}
+
 ////////////////////////
 
 QgsPointPatternFillSymbolLayer::QgsPointPatternFillSymbolLayer(): QgsImageFillSymbolLayer(), mMarkerSymbol( 0 ), mDistanceX( 15 ),
@@ -765,6 +988,49 @@ QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::clone() const
   return clonedLayer;
 }
 
+void QgsPointPatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  for ( int i = 0; i < mMarkerSymbol->symbolLayerCount(); i++ )
+  {
+    QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
+    if ( !props.value( "uom", "" ).isEmpty() )
+      symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
+    element.appendChild( symbolizerElem );
+
+    // <Geometry>
+    QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
+
+    QDomElement fillElem = doc.createElement( "se:Fill" );
+    symbolizerElem.appendChild( fillElem );
+
+    QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
+    fillElem.appendChild( graphicFillElem );
+
+    // store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
+    QString dist =  QgsSymbolLayerV2Utils::encodePoint( QPointF( mDistanceX, mDistanceY ) );
+    QDomElement distanceElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "distance", dist );
+    symbolizerElem.appendChild( distanceElem );
+
+    QgsSymbolLayerV2 *layer = mMarkerSymbol->symbolLayer( i );
+    QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
+    if ( !markerLayer )
+    {
+      QString errorMsg = QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() );
+      graphicFillElem.appendChild( doc.createComment( errorMsg ) );
+    }
+    else
+    {
+      markerLayer->writeSldMarker( doc, graphicFillElem, props );
+    }
+  }
+}
+
+QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::createFromSld( QDomElement &element )
+{
+  Q_UNUSED( element );
+  return NULL;
+}
+
 bool QgsPointPatternFillSymbolLayer::setSubSymbol( QgsSymbolV2* symbol )
 {
   if ( !symbol )
@@ -859,6 +1125,31 @@ QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::clone() const
   return x;
 }
 
+void QgsCentroidFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  // SLD 1.0 specs says: "if a line, polygon, or raster geometry is
+  // used with PointSymbolizer, then the semantic is to use the centroid
+  // of the geometry, or any similar representative point.
+  mMarker->toSld( doc, element, props );
+}
+
+QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::createFromSld( QDomElement &element )
+{
+  QgsDebugMsg( "Entered." );
+
+  QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createMarkerLayerFromSld( element );
+  if ( !l )
+    return NULL;
+
+  QgsSymbolLayerV2List layers;
+  layers.append( l );
+  QgsMarkerSymbolV2 *marker = new QgsMarkerSymbolV2( layers );
+
+  QgsCentroidFillSymbolLayerV2* x = new QgsCentroidFillSymbolLayerV2();
+  x->setSubSymbol( marker );
+  return x;
+}
+
 
 QgsSymbolV2* QgsCentroidFillSymbolLayerV2::subSymbol()
 {
diff --git a/src/core/symbology-ng/qgsfillsymbollayerv2.h b/src/core/symbology-ng/qgsfillsymbollayerv2.h
index 022d031..2adad7d 100644
--- a/src/core/symbology-ng/qgsfillsymbollayerv2.h
+++ b/src/core/symbology-ng/qgsfillsymbollayerv2.h
@@ -25,6 +25,7 @@ class CORE_EXPORT QgsSimpleFillSymbolLayerV2 : public QgsFillSymbolLayerV2
     // static stuff
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     // implemented from base classes
 
@@ -40,6 +41,8 @@ class CORE_EXPORT QgsSimpleFillSymbolLayerV2 : public QgsFillSymbolLayerV2
 
     QgsSymbolLayerV2* clone() const;
 
+    void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     Qt::BrushStyle brushStyle() const { return mBrushStyle; }
     void setBrushStyle( Qt::BrushStyle style ) { mBrushStyle = style; }
 
@@ -97,6 +100,7 @@ class CORE_EXPORT QgsSVGFillSymbolLayer: public QgsImageFillSymbolLayer
     ~QgsSVGFillSymbolLayer();
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     // implemented from base classes
 
@@ -109,6 +113,8 @@ class CORE_EXPORT QgsSVGFillSymbolLayer: public QgsImageFillSymbolLayer
 
     QgsSymbolLayerV2* clone() const;
 
+    void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     //getters and setters
     void setSvgFilePath( const QString& svgPath );
     QString svgFilePath() const { return mSvgFilePath; }
@@ -151,6 +157,7 @@ class CORE_EXPORT QgsLinePatternFillSymbolLayer: public QgsImageFillSymbolLayer
     ~QgsLinePatternFillSymbolLayer();
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     QString layerType() const;
 
@@ -162,6 +169,8 @@ class CORE_EXPORT QgsLinePatternFillSymbolLayer: public QgsImageFillSymbolLayer
 
     QgsSymbolLayerV2* clone() const;
 
+    void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     //getters and setters
     void setLineAngle( double a ) { mLineAngle = a; }
     double lineAngle() const { return mLineAngle; }
@@ -193,6 +202,8 @@ class CORE_EXPORT QgsPointPatternFillSymbolLayer: public QgsImageFillSymbolLayer
     ~QgsPointPatternFillSymbolLayer();
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
+
     QString layerType() const;
 
     void startRender( QgsSymbolV2RenderContext& context );
@@ -203,6 +214,8 @@ class CORE_EXPORT QgsPointPatternFillSymbolLayer: public QgsImageFillSymbolLayer
 
     QgsSymbolLayerV2* clone() const;
 
+    void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     //getters and setters
     double distanceX() const { return mDistanceX; }
     void setDistanceX( double d ) { mDistanceX = d; }
@@ -236,6 +249,7 @@ class CORE_EXPORT QgsCentroidFillSymbolLayerV2 : public QgsFillSymbolLayerV2
     // static stuff
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     // implemented from base classes
 
@@ -251,6 +265,8 @@ class CORE_EXPORT QgsCentroidFillSymbolLayerV2 : public QgsFillSymbolLayerV2
 
     QgsSymbolLayerV2* clone() const;
 
+    void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     void setColor( const QColor& color );
 
     QgsSymbolV2* subSymbol();
diff --git a/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp b/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
index 1f7691d..190c95b 100644
--- a/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
+++ b/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
@@ -98,6 +98,38 @@ QString QgsRendererRangeV2::dump()
   return QString( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel ).arg( mSymbol->dump() );
 }
 
+void QgsRendererRangeV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  if ( !mSymbol || props.value( "attribute", "" ).isEmpty() )
+    return;
+
+  QDomElement ruleElem = doc.createElement( "se:Rule" );
+  element.appendChild( ruleElem );
+
+  QString valueStr = QString( "range: %1 - %2" ).arg( mLowerValue ).arg( mUpperValue );
+
+  QDomElement nameElem = doc.createElement( "se:Name" );
+  nameElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : valueStr ) );
+  ruleElem.appendChild( nameElem );
+
+  QString descrName = props.value( "version", "1.1" ) < "1.1" ? "Abstract" : "se:Description";
+  QString descrValue = QString( "Graduated symbol rendererV2 - %1" ).arg( valueStr );
+
+  QDomElement descrElem = doc.createElement( descrName );
+  descrElem.appendChild( doc.createTextNode( descrValue ) );
+  ruleElem.appendChild( descrElem );
+
+  // create the ogc:Filter for the range
+  QDomElement filterElem = doc.createElement( "ogc:Filter" );
+
+  QString filterFunc = QString( "%1 > %2 AND %1 <= %3" )
+      .arg( props[ "attribute" ] )
+      .arg( mLowerValue ).arg( mUpperValue );
+  QgsSymbolLayerV2Utils::createFunctionElement( doc, filterElem, filterFunc );
+
+  mSymbol->toSld( doc, ruleElem, props );
+}
+
 ///////////
 
 QgsGraduatedSymbolRendererV2::QgsGraduatedSymbolRendererV2( QString attrName, QgsRangeList ranges )
@@ -302,6 +334,23 @@ QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2::clone()
   return r;
 }
 
+void QgsGraduatedSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
+{
+  QgsStringMap props;
+  props[ "attribute" ] = mAttrName;
+  if ( !mRotationField.isEmpty() )
+    props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
+  if ( !mSizeScaleField.isEmpty() )
+    props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );
+
+  // create a Rule for each range
+  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); it++ )
+  {
+    QgsStringMap catProps( props );
+    it->toSld( doc, element, catProps );
+  }
+}
+
 QgsSymbolV2List QgsGraduatedSymbolRendererV2::symbols()
 {
   QgsSymbolV2List lst;
diff --git a/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h b/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h
index de0f4c6..a10da2b 100644
--- a/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h
+++ b/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h
@@ -1,6 +1,7 @@
 #ifndef QGSGRADUATEDSYMBOLRENDERERV2_H
 #define QGSGRADUATEDSYMBOLRENDERERV2_H
 
+#include "qgssymbolv2.h"
 #include "qgsrendererv2.h"
 
 class CORE_EXPORT QgsRendererRangeV2
@@ -25,6 +26,8 @@ class CORE_EXPORT QgsRendererRangeV2
     // debugging
     QString dump();
 
+    void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;
+
   protected:
     double mLowerValue, mUpperValue;
     QgsSymbolV2* mSymbol;
@@ -55,6 +58,8 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
 
     virtual QgsFeatureRendererV2* clone();
 
+    virtual void toSld( QDomDocument& doc, QDomElement &element ) const;
+
     //! returns bitwise OR-ed capabilities of the renderer
     //! \note added in 2.0
     virtual int capabilities() { return SymbolLevels | RotationField; }
diff --git a/src/core/symbology-ng/qgslinesymbollayerv2.cpp b/src/core/symbology-ng/qgslinesymbollayerv2.cpp
index ff6ef8b..b4ec8e0 100644
--- a/src/core/symbology-ng/qgslinesymbollayerv2.cpp
+++ b/src/core/symbology-ng/qgslinesymbollayerv2.cpp
@@ -3,8 +3,11 @@
 #include "qgssymbollayerv2utils.h"
 
 #include "qgsrendercontext.h"
+#include "qgslogger.h"
 
 #include <QPainter>
+#include <QDomDocument>
+#include <QDomElement>
 
 #include <cmath>
 
@@ -148,6 +151,77 @@ QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::clone() const
   return l;
 }
 
+void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  if ( mPenStyle == Qt::NoPen )
+    return;
+
+  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
+  if ( !props.value( "uom", "" ).isEmpty() )
+    symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
+  element.appendChild( symbolizerElem );
+
+  // <Geometry>
+  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
+
+  // <Stroke>
+  QDomElement strokeElem = doc.createElement( "se:Stroke" );
+  symbolizerElem.appendChild( strokeElem );
+
+  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
+  QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
+                                    &mPenJoinStyle, &mPenCapStyle, &mCustomDashVector );
+
+  // <se:PerpendicularOffset>
+  if ( mOffset != 0 )
+  {
+    QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
+    perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
+    symbolizerElem.appendChild( perpOffsetElem );
+  }
+}
+
+QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::createFromSld( QDomElement &element )
+{
+  QgsDebugMsg( "Entered." );
+
+  QDomElement strokeElem = element.firstChildElement( "Stroke" );
+  if ( strokeElem.isNull() )
+    return NULL;
+
+  Qt::PenStyle penStyle;
+  QColor color;
+  double width;
+  Qt::PenJoinStyle penJoinStyle;
+  Qt::PenCapStyle penCapStyle;
+  QVector<qreal> customDashVector;
+
+  if ( !QgsSymbolLayerV2Utils::lineFromSld( strokeElem, penStyle,
+                                            color, width,
+                                            &penJoinStyle, &penCapStyle,
+                                            &customDashVector ) )
+    return NULL;
+
+  double offset = 0.0;
+  QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
+  if ( !perpOffsetElem.isNull() )
+  {
+    bool ok;
+    double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
+    if ( ok )
+      offset = d;
+  }
+
+  QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
+  l->setOffset( offset );
+  l->setPenJoinStyle( penJoinStyle );
+  l->setPenCapStyle( penCapStyle );
+  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
+  l->setCustomDashVector( customDashVector );
+  return l;
+}
+
+
 
 /////////
 
@@ -574,6 +648,154 @@ QgsSymbolLayerV2* QgsMarkerLineSymbolLayerV2::clone() const
   return x;
 }
 
+void QgsMarkerLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
+  {
+    QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
+    if ( !props.value( "uom", "" ).isEmpty() )
+      symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
+    element.appendChild( symbolizerElem );
+
+    // <Geometry>
+    QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
+
+    QString gap;
+    switch( mPlacement )
+    {
+      case FirstVertex:
+        symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) );
+        break;
+      case LastVertex:
+        symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
+        break;
+      case CentralPoint:
+        symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) );
+        break;
+      case Vertex:
+        // no way to get line/polygon's vertices, use a VendorOption
+        symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
+        break;
+      default:
+        gap = QString::number( mInterval );
+        break;
+    }
+
+    if( !mRotateMarker )
+    {
+      // markers in LineSymbolizer must be drawn following the line orientation,
+      // use a VendorOption when no marker rotation
+      symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) );
+    }
+
+    // <Stroke>
+    QDomElement strokeElem = doc.createElement( "se:Stroke" );
+    symbolizerElem.appendChild( strokeElem );
+
+    // <GraphicStroke>
+    QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
+    strokeElem.appendChild( graphicStrokeElem );
+
+    QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i );
+    QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
+    if ( !markerLayer )
+    {
+      graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( markerLayer->layerType() ) ) );
+    }
+    else
+    {
+      markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
+    }
+
+    if ( !gap.isEmpty() )
+    {
+      QDomElement gapElem = doc.createElement( "se:Gap" );
+      QgsSymbolLayerV2Utils::createFunctionElement( doc, gapElem, gap );
+      graphicStrokeElem.appendChild( gapElem );
+    }
+
+    if ( !doubleNear( mOffset, 0.0 ) )
+    {
+      QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
+      perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
+      symbolizerElem.appendChild( perpOffsetElem );
+    }
+  }
+}
+
+QgsSymbolLayerV2* QgsMarkerLineSymbolLayerV2::createFromSld( QDomElement &element )
+{
+  QgsDebugMsg( "Entered." );
+
+  QDomElement strokeElem = element.firstChildElement( "Stroke" );
+  if ( strokeElem.isNull() )
+    return NULL;
+
+  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
+  if ( graphicStrokeElem.isNull() )
+    return NULL;
+
+  // retrieve vendor options
+  bool rotateMarker = true;
+  Placement placement = Interval;
+
+  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( element );
+  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
+  {
+    if ( it.key() == "placement" )
+    {
+      if ( it.value() == "points" ) placement = Vertex;
+      else if ( it.value() == "firstPoint" ) placement = FirstVertex;
+      else if ( it.value() == "lastPoint" ) placement = LastVertex;
+      else if ( it.value() == "centralPoint" ) placement = CentralPoint;
+    }
+    else if ( it.value() == "rotateMarker" )
+    {
+      rotateMarker = it.value() == "0";
+    }
+  }
+
+  QgsMarkerSymbolV2 *marker = 0;
+
+  QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createMarkerLayerFromSld( graphicStrokeElem );
+  if ( l )
+  {
+    QgsSymbolLayerV2List layers;
+    layers.append( l );
+    marker = new QgsMarkerSymbolV2( layers );
+  }
+
+  double interval = 0.0;
+  QDomElement gapElem = element.firstChildElement( "Gap" );
+  if ( !gapElem.isNull() )
+  {
+    bool ok;
+    double d = gapElem.firstChild().nodeValue().toDouble( &ok );
+    if ( ok )
+      interval = d;
+  }
+
+  double offset = 0.0;
+  QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
+  if ( !perpOffsetElem.isNull() )
+  {
+    bool ok;
+    double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
+    if ( ok )
+      offset = d;
+  }
+
+  QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
+  x->setPlacement( placement );
+  if ( !doubleNear( interval, 0.0 ) && interval > 0 )
+    x->setInterval( interval );
+  if ( marker )
+    x->setSubSymbol( marker );
+  if ( !doubleNear( offset, 0.0 ) )
+    x->setOffset( offset );
+  return x;
+}
+
 void QgsMarkerLineSymbolLayerV2::setWidth( double width )
 {
   mMarker->setSize( width );
@@ -683,3 +905,34 @@ QgsSymbolLayerV2* QgsLineDecorationSymbolLayerV2::clone() const
 {
   return new QgsLineDecorationSymbolLayerV2( mColor, mWidth );
 }
+
+void QgsLineDecorationSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
+  if ( !props.value( "uom", "" ).isEmpty() )
+    symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
+  element.appendChild( symbolizerElem );
+
+  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom" , "" ) );
+
+  // <Stroke>
+  QDomElement strokeElem = doc.createElement( "se:Stroke" );
+  symbolizerElem.appendChild( strokeElem );
+
+  // <GraphicStroke>
+  QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
+  strokeElem.appendChild( graphicStrokeElem );
+
+  // <Graphic>
+  QDomElement graphicElem = doc.createElement( "se:Graphic" );
+  graphicStrokeElem.appendChild( graphicElem );
+
+  // <Mark>
+  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "arrowhead", QColor(), mColor, mWidth, mWidth*8 );
+
+  // <Rotation>
+  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, props.value( "angle", "" ) );
+
+  // use <VendorOption> to draw the decoration at end of the line
+  symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
+}
diff --git a/src/core/symbology-ng/qgslinesymbollayerv2.h b/src/core/symbology-ng/qgslinesymbollayerv2.h
index 8d99357..d7502c6 100644
--- a/src/core/symbology-ng/qgslinesymbollayerv2.h
+++ b/src/core/symbology-ng/qgslinesymbollayerv2.h
@@ -24,6 +24,7 @@ class CORE_EXPORT QgsSimpleLineSymbolLayerV2 : public QgsLineSymbolLayerV2
     // static stuff
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     // implemented from base classes
 
@@ -39,6 +40,8 @@ class CORE_EXPORT QgsSimpleLineSymbolLayerV2 : public QgsLineSymbolLayerV2
 
     QgsSymbolLayerV2* clone() const;
 
+    void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     // new stuff
 
     Qt::PenStyle penStyle() const { return mPenStyle; }
@@ -97,6 +100,7 @@ class CORE_EXPORT QgsMarkerLineSymbolLayerV2 : public QgsLineSymbolLayerV2
     // static stuff
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     // implemented from base classes
 
@@ -112,6 +116,8 @@ class CORE_EXPORT QgsMarkerLineSymbolLayerV2 : public QgsLineSymbolLayerV2
 
     QgsSymbolLayerV2* clone() const;
 
+    void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     void setColor( const QColor& color );
 
     QgsSymbolV2* subSymbol();
@@ -163,6 +169,7 @@ class CORE_EXPORT QgsLineDecorationSymbolLayerV2 : public QgsLineSymbolLayerV2
     // static stuff
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     // implemented from base classes
 
@@ -178,6 +185,8 @@ class CORE_EXPORT QgsLineDecorationSymbolLayerV2 : public QgsLineSymbolLayerV2
 
     QgsSymbolLayerV2* clone() const;
 
+    void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
   protected:
     QPen mPen;
     QPen mSelPen;
diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
index 31df9bf..69fa683 100644
--- a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
+++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
@@ -12,6 +12,8 @@
 #include <QSvgRenderer>
 #include <QFileInfo>
 #include <QDir>
+#include <QDomDocument>
+#include <QDomElement>
 
 #include <cmath>
 
@@ -34,6 +36,8 @@ static QPointF _rotatedOffset( const QPointF& offset, double angle )
 
 QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( QString name, QColor color, QColor borderColor, double size, double angle )
 {
+  if ( name == "rectangle" )
+    name = "square";
   mName = name;
   mColor = color;
   mBorderColor = borderColor;
@@ -222,7 +226,7 @@ bool QgsSimpleMarkerSymbolLayerV2::prepareShape()
 {
   mPolygon.clear();
 
-  if ( mName == "rectangle" )
+  if ( mName == "square" )
   {
     mPolygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
     return true;
@@ -324,7 +328,7 @@ bool QgsSimpleMarkerSymbolLayerV2::preparePath()
     mPath.lineTo( 0, 1 ); // vertical
     return true;
   }
-  else if ( mName == "cross2" )
+  else if ( mName == "x" || mName == "cross2" )
   {
     mPath.moveTo( -1, -1 );
     mPath.lineTo( 1, 1 );
@@ -426,6 +430,66 @@ QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::clone() const
   return m;
 }
 
+void QgsSimpleMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  // <Graphic>
+  QDomElement graphicElem = doc.createElement( "se:Graphic" );
+  element.appendChild( graphicElem );
+
+  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mName, mColor, mBorderColor, -1, mSize );
+
+  // <Rotation>
+  QString angleFunc;
+  bool ok;
+  double angle = props.value( "angle", "0" ).toDouble( &ok );
+  if ( !ok )
+  {
+    angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
+  }
+  else if ( angle + mAngle != 0 )
+  {
+    angleFunc = QString::number( angle + mAngle );
+  }
+  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
+
+  // <Displacement>
+  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
+}
+
+QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::createFromSld( QDomElement &element )
+{
+  QgsDebugMsg( "Entered." );
+
+  QDomElement graphicElem = element.firstChildElement( "Graphic" );
+  if( graphicElem.isNull() )
+    return NULL;
+
+  QString name = "square";
+  QColor color, borderColor;
+  double borderWidth, size;
+
+  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderWidth, size ) )
+    return NULL;
+
+  double angle = 0.0;
+  QString angleFunc;
+  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
+  {
+    bool ok;
+    double d = angleFunc.toDouble( &ok );
+    if ( ok )
+      angle = d;
+  }
+
+  QPointF offset;
+  QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
+
+  QgsMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size );
+  m->setAngle( angle );
+  m->setOffset( offset );
+  return m;
+}
+
 void QgsSimpleMarkerSymbolLayerV2::drawMarker( QPainter* p, QgsSymbolV2RenderContext& context )
 {
   Q_UNUSED( context );
@@ -627,6 +691,73 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const
   return m;
 }
 
+void QgsSvgMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  // <Graphic>
+  QDomElement graphicElem = doc.createElement( "se:Graphic" );
+  element.appendChild( graphicElem );
+
+  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mFillColor, mSize );
+
+  // <Rotation>
+  QString angleFunc;
+  bool ok;
+  double angle = props.value( "angle", "0" ).toDouble( &ok );
+  if ( !ok )
+  {
+    angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
+  }
+  else if ( angle + mAngle != 0 )
+  {
+    angleFunc = QString::number( angle + mAngle );
+  }
+
+  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
+
+  // <Displacement>
+  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
+}
+
+QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::createFromSld( QDomElement &element )
+{
+  QgsDebugMsg( "Entered." );
+
+  QDomElement graphicElem = element.firstChildElement( "Graphic" );
+  if( graphicElem.isNull() )
+    return NULL;
+
+  QString path, mimeType;
+  QColor fillColor;
+  double size;
+
+  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
+    return NULL;
+
+  if ( mimeType != "image/svg+xml" )
+    return NULL;
+
+  double angle = 0.0;
+  QString angleFunc;
+  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
+  {
+    bool ok;
+    double d = angleFunc.toDouble( &ok );
+    if ( ok )
+      angle = d;
+  }
+
+  QPointF offset;
+  QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
+
+  QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( path, size );
+  m->setFillColor( fillColor );
+  //m->setOutlineColor( outlineColor );
+  //m->setOutlineWidth( outlineWidth );
+  m->setAngle( angle );
+  m->setOffset( offset );
+  return m;
+}
+
 
 QStringList QgsSvgMarkerSymbolLayerV2::listSvgFiles()
 {
@@ -829,3 +960,71 @@ QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::clone() const
   m->setOffset( mOffset );
   return m;
 }
+
+void QgsFontMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  // <Graphic>
+  QDomElement graphicElem = doc.createElement( "se:Graphic" );
+  element.appendChild( graphicElem );
+
+  QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
+  int markIndex = mChr.unicode();
+  QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
+
+  // <Rotation>
+  QString angleFunc;
+  bool ok;
+  double angle = props.value( "angle", "0" ).toDouble( &ok );
+  if ( !ok )
+  {
+    angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
+  }
+  else if ( angle + mAngle != 0 )
+  {
+    angleFunc = QString::number( angle + mAngle );
+  }
+  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
+
+  // <Displacement>
+  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
+}
+
+QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::createFromSld( QDomElement &element )
+{
+  QgsDebugMsg( "Entered." );
+
+  QDomElement graphicElem = element.firstChildElement( "Graphic" );
+  if( graphicElem.isNull() )
+    return NULL;
+
+  QString name, format;
+  QColor color;
+  double size;
+  int chr;
+
+  if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
+    return NULL;
+
+  if ( !name.startsWith( "ttf://" ) || format != "ttf" )
+    return NULL;
+
+  QString fontFamily = name.mid( 6 );
+
+  double angle = 0.0;
+  QString angleFunc;
+  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
+  {
+    bool ok;
+    double d = angleFunc.toDouble( &ok );
+    if ( ok )
+      angle = d;
+  }
+
+  QPointF offset;
+  QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
+
+  QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
+  m->setAngle( angle );
+  m->setOffset( offset );
+  return m;
+}
diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.h b/src/core/symbology-ng/qgsmarkersymbollayerv2.h
index 705721c..3cbec0a 100644
--- a/src/core/symbology-ng/qgsmarkersymbollayerv2.h
+++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.h
@@ -28,6 +28,7 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
     // static stuff
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     // implemented from base classes
 
@@ -43,6 +44,8 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
 
     QgsSymbolLayerV2* clone() const;
 
+    void writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     QString name() const { return mName; }
     void setName( QString name ) { mName = name; }
 
@@ -87,6 +90,7 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
     // static stuff
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     //! Return a list of all available svg files
     static QStringList listSvgFiles();
@@ -111,6 +115,8 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
 
     QgsSymbolLayerV2* clone() const;
 
+    void writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     QString path() const { return mPath; }
     void setPath( QString path );
 
@@ -161,6 +167,7 @@ class CORE_EXPORT QgsFontMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
     // static stuff
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     // implemented from base classes
 
@@ -176,6 +183,8 @@ class CORE_EXPORT QgsFontMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
 
     QgsSymbolLayerV2* clone() const;
 
+    void writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     // new methods
 
     QString fontFamily() const { return mFontFamily; }
diff --git a/src/core/symbology-ng/qgspointdisplacementrenderer.cpp b/src/core/symbology-ng/qgspointdisplacementrenderer.cpp
index a822770..affcddd 100644
--- a/src/core/symbology-ng/qgspointdisplacementrenderer.cpp
+++ b/src/core/symbology-ng/qgspointdisplacementrenderer.cpp
@@ -22,8 +22,10 @@
 #include "qgssymbolv2.h"
 #include "qgssymbollayerv2utils.h"
 #include "qgsvectorlayer.h"
+
 #include <QDomElement>
 #include <QPainter>
+
 #include <cmath>
 
 QgsPointDisplacementRenderer::QgsPointDisplacementRenderer( const QString& labelAttributeName )
@@ -66,6 +68,12 @@ QgsFeatureRendererV2* QgsPointDisplacementRenderer::clone()
   return r;
 }
 
+void QgsPointDisplacementRenderer::toSld( QDomDocument& doc, QDomElement &element ) const
+{
+  mRenderer->toSld( doc, element );
+}
+
+
 bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
 {
   Q_UNUSED( drawVertexMarker );
diff --git a/src/core/symbology-ng/qgspointdisplacementrenderer.h b/src/core/symbology-ng/qgspointdisplacementrenderer.h
index a8f9270..856d519 100644
--- a/src/core/symbology-ng/qgspointdisplacementrenderer.h
+++ b/src/core/symbology-ng/qgspointdisplacementrenderer.h
@@ -36,6 +36,8 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsFeatureRendererV2
 
     QgsFeatureRendererV2* clone();
 
+    virtual void toSld( QDomDocument& doc, QDomElement &element ) const;
+
     /**Reimplemented from QgsFeatureRendererV2*/
     bool renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false );
 
diff --git a/src/core/symbology-ng/qgsrendererv2.cpp b/src/core/symbology-ng/qgsrendererv2.cpp
index be5ab2b..36faa5f 100644
--- a/src/core/symbology-ng/qgsrendererv2.cpp
+++ b/src/core/symbology-ng/qgsrendererv2.cpp
@@ -372,6 +372,110 @@ QDomElement QgsFeatureRendererV2::save( QDomDocument& doc )
   return doc.createElement( RENDERER_TAG_NAME );
 }
 
+QgsFeatureRendererV2* QgsFeatureRendererV2::loadSld( const QDomNode &node, QGis::GeometryType geomType, QString &errorMessage )
+{
+  QDomElement element = node.toElement();
+  if ( element.isNull() )
+    return NULL;
+
+  // get the UserStyle element
+  QDomElement userStyleElem = element.firstChildElement( "UserStyle" );
+  if ( userStyleElem.isNull() )
+  {
+    // UserStyle element not found, nothing will be rendered
+    errorMessage = "Info: UserStyle element not found.";
+    return NULL;
+  }
+
+  // get the FeatureTypeStyle element
+  QDomElement featTypeStyleElem = userStyleElem.firstChildElement( "FeatureTypeStyle" );
+  if ( featTypeStyleElem.isNull() )
+  {
+    errorMessage = "Info: FeatureTypeStyle element not found.";
+    return NULL;
+  }
+
+  // use the RuleRenderer when more rules are present or the rule
+  // has filters or min/max scale denominators set,
+  // otherwise use the SingleSymbol renderer
+  bool needRuleRenderer = false;
+  int ruleCount = 0;
+
+  QDomElement ruleElem = featTypeStyleElem.firstChildElement( "Rule" );
+  while( !ruleElem.isNull() )
+  {
+    ruleCount++;
+
+    // more rules present, use the RuleRenderer
+    if ( ruleCount > 1 )
+    {
+      QgsDebugMsg( "more Rule elements found: need a RuleRenderer" );
+      needRuleRenderer = true;
+      break;
+    }
+
+    QDomElement ruleChildElem = ruleElem.firstChildElement();
+    while( !ruleChildElem.isNull() )
+    {
+      // rule has filter or min/max scale denominator, use the RuleRenderer
+      if ( ruleChildElem.localName() == "Filter" ||
+           ruleChildElem.localName() == "MinScaleDenominator" ||
+           ruleChildElem.localName() == "MaxScaleDenominator" )
+      {
+        QgsDebugMsg( "Filter or Min/MaxScaleDenominator element found: need a RuleRenderer" );
+        needRuleRenderer = true;
+        break;
+      }
+
+      ruleChildElem = ruleChildElem.nextSiblingElement();
+    }
+
+    if ( needRuleRenderer )
+    {
+      break;
+    }
+
+    ruleElem = ruleElem.nextSiblingElement( "Rule" );
+  }
+
+  QString rendererType;
+  if ( needRuleRenderer )
+  {
+    rendererType = "RuleRenderer";
+  }
+  else
+  {
+    rendererType = "singleSymbol";
+  }
+  QgsDebugMsg( QString( "Instantiating a '%1' renderer..." ).arg( rendererType ) );
+
+  // create the renderer and return it
+  QgsRendererV2AbstractMetadata* m = QgsRendererV2Registry::instance()->rendererMetadata( rendererType );
+  if ( m == NULL )
+  {
+    errorMessage = QString( "Error: Unable to get metadata for '%1' renderer." ).arg( rendererType );
+    return NULL;
+  }
+
+  QgsFeatureRendererV2* r = m->createRendererFromSld( featTypeStyleElem, geomType );
+  return r;
+}
+
+QDomElement QgsFeatureRendererV2::writeSld( QDomDocument& doc, const QgsVectorLayer &layer ) const
+{
+  QDomElement userStyleElem = doc.createElement( "UserStyle" );
+
+  QDomElement nameElem = doc.createElement( "se:Name" );
+  nameElem.appendChild( doc.createTextNode( layer.name() ) );
+  userStyleElem.appendChild( nameElem );
+
+  QDomElement featureTypeStyleElem = doc.createElement( "se:FeatureTypeStyle" );
+  toSld( doc, featureTypeStyleElem );
+  userStyleElem.appendChild( featureTypeStyleElem );
+
+  return userStyleElem;
+}
+
 QgsLegendSymbologyList QgsFeatureRendererV2::legendSymbologyItems( QSize iconSize )
 {
   Q_UNUSED( iconSize );
diff --git a/src/core/symbology-ng/qgsrendererv2.h b/src/core/symbology-ng/qgsrendererv2.h
index 968e8e8..4d9f1ef 100644
--- a/src/core/symbology-ng/qgsrendererv2.h
+++ b/src/core/symbology-ng/qgsrendererv2.h
@@ -9,15 +9,16 @@
 #include <QVariant>
 #include <QPair>
 #include <QPixmap>
-
-class QDomDocument;
-class QDomElement;
+#include <QDomDocument>
+#include <QDomElement>
 
 class QgsSymbolV2;
 class QgsRenderContext;
 class QgsFeature;
 class QgsVectorLayer;
 
+typedef QMap<QString, QString> QgsStringMap;
+
 typedef QList<QgsSymbolV2*> QgsSymbolV2List;
 typedef QMap<QString, QgsSymbolV2* > QgsSymbolV2Map;
 
@@ -101,6 +102,28 @@ class CORE_EXPORT QgsFeatureRendererV2
     //! store renderer info to XML element
     virtual QDomElement save( QDomDocument& doc );
 
+    //! create the SLD UserStyle element following the SLD v1.1 specs
+    //! @note added in 1.9
+    virtual QDomElement writeSld( QDomDocument& doc, const QgsVectorLayer &layer ) const;
+
+    /** create a new renderer according to the information contained in
+     * the UserStyle element of a SLD style document
+     * @param node the node in the SLD document whose the UserStyle element
+     * is a child
+     * @param geomType the geometry type of the features, used to convert
+     * Symbolizer elements
+     * @param errorMessage it will contain the error message if something
+     * went wrong
+     * @return the renderer
+     * @note added in 1.9
+     */
+    static QgsFeatureRendererV2* loadSld( const QDomNode &node, QGis::GeometryType geomType, QString &errorMessage );
+
+    //! used from subclasses to create SLD Rule elements following SLD v1.1 specs
+    //! @note added in 1.9
+    virtual void toSld( QDomDocument& doc, QDomElement &element ) const
+    { element.appendChild( doc.createComment( QString( "FeatureRendererV2 %1 not implemented yet" ).arg( type() ) ) ); }
+
     //! return a list of symbology items for the legend
     virtual QgsLegendSymbologyList legendSymbologyItems( QSize iconSize );
 
@@ -162,4 +185,4 @@ class CORE_EXPORT QgsFeatureRendererV2
 };
 
 
-#endif
+#endif // QGSRENDERERV2_H
diff --git a/src/core/symbology-ng/qgsrendererv2registry.cpp b/src/core/symbology-ng/qgsrendererv2registry.cpp
index eb4bf3a..2ae673d 100644
--- a/src/core/symbology-ng/qgsrendererv2registry.cpp
+++ b/src/core/symbology-ng/qgsrendererv2registry.cpp
@@ -14,7 +14,9 @@ QgsRendererV2Registry::QgsRendererV2Registry()
   // add default renderers
   addRenderer( new QgsRendererV2Metadata( "singleSymbol",
                                           QObject::tr( "Single Symbol" ),
-                                          QgsSingleSymbolRendererV2::create ) );
+                                          QgsSingleSymbolRendererV2::create,
+                                          QgsSingleSymbolRendererV2::createFromSld ) );
+
   addRenderer( new QgsRendererV2Metadata( "categorizedSymbol",
                                           QObject::tr( "Categorized" ),
                                           QgsCategorizedSymbolRendererV2::create ) );
@@ -24,7 +26,9 @@ QgsRendererV2Registry::QgsRendererV2Registry()
 
   addRenderer( new QgsRendererV2Metadata( "RuleRenderer",
                                           QObject::tr( "Rule-based" ),
-                                          QgsRuleBasedRendererV2::create ) );
+                                          QgsRuleBasedRendererV2::create,
+                                          QgsRuleBasedRendererV2::createFromSld ) );
+
   addRenderer( new QgsRendererV2Metadata( "pointDisplacement",
                                           QObject::tr( "Point displacement" ),
                                           QgsPointDisplacementRenderer::create ) );
diff --git a/src/core/symbology-ng/qgsrendererv2registry.h b/src/core/symbology-ng/qgsrendererv2registry.h
index 535ec4b..ed274c9 100644
--- a/src/core/symbology-ng/qgsrendererv2registry.h
+++ b/src/core/symbology-ng/qgsrendererv2registry.h
@@ -5,6 +5,8 @@
 #include <QMap>
 #include <QStringList>
 
+#include "qgis.h"
+
 class QgsFeatureRendererV2;
 class QDomElement;
 class QgsVectorLayer;
@@ -37,6 +39,9 @@ class CORE_EXPORT QgsRendererV2AbstractMetadata
     virtual QgsRendererV2Widget* createRendererWidget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
     { Q_UNUSED( layer ); Q_UNUSED( style ); Q_UNUSED( renderer ); return NULL; }
 
+    virtual QgsFeatureRendererV2* createRendererFromSld( QDomElement& elem, QGis::GeometryType geomType )
+    { Q_UNUSED( elem ); Q_UNUSED( geomType ); return NULL; }
+
   protected:
     //! name used within QGIS for identification (the same what renderer's type() returns)
     QString mName;
@@ -49,6 +54,7 @@ class CORE_EXPORT QgsRendererV2AbstractMetadata
 
 typedef QgsFeatureRendererV2*( *QgsRendererV2CreateFunc )( QDomElement& );
 typedef QgsRendererV2Widget*( *QgsRendererV2WidgetFunc )( QgsVectorLayer*, QgsStyleV2*, QgsFeatureRendererV2* );
+typedef QgsFeatureRendererV2*( *QgsRendererV2CreateFromSldFunc )( QDomElement&, QGis::GeometryType geomType );
 
 /**
  Convenience metadata class that uses static functions to create renderer and its widget.
@@ -63,14 +69,28 @@ class CORE_EXPORT QgsRendererV2Metadata : public QgsRendererV2AbstractMetadata
                            QgsRendererV2CreateFunc pfCreate,
                            QIcon icon = QIcon(),
                            QgsRendererV2WidgetFunc pfWidget = NULL )
-        : QgsRendererV2AbstractMetadata( name, visibleName, icon ), mCreateFunc( pfCreate ), mWidgetFunc( pfWidget ) {}
+        : QgsRendererV2AbstractMetadata( name, visibleName, icon ),
+          mCreateFunc( pfCreate ), mWidgetFunc( pfWidget ), mCreateFromSldFunc( NULL ) {}
+
+    QgsRendererV2Metadata( QString name,
+                           QString visibleName,
+                           QgsRendererV2CreateFunc pfCreate,
+                           QgsRendererV2CreateFromSldFunc pfCreateFromSld,
+                           QIcon icon = QIcon(),
+                           QgsRendererV2WidgetFunc pfWidget = NULL )
+      : QgsRendererV2AbstractMetadata( name, visibleName, icon ),
+        mCreateFunc( pfCreate ), mWidgetFunc( pfWidget ), mCreateFromSldFunc( pfCreateFromSld ) {}
 
     virtual QgsFeatureRendererV2* createRenderer( QDomElement& elem ) { return mCreateFunc ? mCreateFunc( elem ) : NULL; }
     virtual QgsRendererV2Widget* createRendererWidget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
     { return mWidgetFunc ? mWidgetFunc( layer, style, renderer ) : NULL; }
+    virtual QgsFeatureRendererV2* createRendererFromSld( QDomElement& elem, QGis::GeometryType geomType )
+    { return mCreateFromSldFunc ? mCreateFromSldFunc( elem, geomType ) : NULL; }
+
 
     QgsRendererV2CreateFunc createFunction() const { return mCreateFunc; }
     QgsRendererV2WidgetFunc widgetFunction() const { return mWidgetFunc; }
+    QgsRendererV2CreateFromSldFunc createFromSldFunction() const { return mCreateFromSldFunc; }
 
     void setWidgetFunction( QgsRendererV2WidgetFunc f ) { mWidgetFunc = f; }
 
@@ -79,6 +99,8 @@ class CORE_EXPORT QgsRendererV2Metadata : public QgsRendererV2AbstractMetadata
     QgsRendererV2CreateFunc mCreateFunc;
     //! pointer to function that creates a widget for configuration of renderer's params
     QgsRendererV2WidgetFunc mWidgetFunc;
+    //! pointer to function that creates an instance of the renderer from SLD
+    QgsRendererV2CreateFromSldFunc mCreateFromSldFunc;
 };
 
 /**
diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp
index 665ec9d..fa75d74 100644
--- a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp
+++ b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp
@@ -188,6 +188,88 @@ QDomElement QgsRuleBasedRendererV2::Rule::save( QDomDocument& doc, QgsSymbolV2Ma
   return ruleElem;
 }
 
+void QgsRuleBasedRendererV2::Rule::toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props )
+{
+  // do not convert this rule if there are no symbols
+  if ( symbols().isEmpty() )
+    return;
+
+  if ( !mFilterExp.isEmpty() )
+  {
+    if ( !props.value( "filter", "" ).isEmpty() )
+      props[ "filter" ] += " AND ";
+    props[ "filter" ] += mFilterExp;
+  }
+
+  if ( mScaleMinDenom != 0 )
+  {
+    bool ok;
+    int parentScaleMinDenom = props.value( "scaleMinDenom", "0" ).toInt( &ok );
+    if ( !ok || parentScaleMinDenom <= 0 )
+      props[ "scaleMinDenom" ] = QString::number( mScaleMinDenom );
+    else
+      props[ "scaleMinDenom" ] = QString::number( qMax( parentScaleMinDenom, mScaleMinDenom ) );
+  }
+
+  if ( mScaleMaxDenom != 0 )
+  {
+    bool ok;
+    int parentScaleMaxDenom = props.value( "scaleMaxDenom", "0" ).toInt( &ok );
+    if ( !ok || parentScaleMaxDenom <= 0 )
+      props[ "scaleMaxDenom" ] = QString::number( mScaleMaxDenom );
+    else
+      props[ "scaleMaxDenom" ] = QString::number( qMin( parentScaleMaxDenom, mScaleMaxDenom ) );
+  }
+
+  if ( mSymbol )
+  {
+    QDomElement ruleElem = doc.createElement( "se:Rule" );
+    element.appendChild( ruleElem );
+
+    QDomElement nameElem = doc.createElement( "se:Name" );
+    nameElem.appendChild( doc.createTextNode( mLabel ) );
+    ruleElem.appendChild( nameElem );
+
+    if ( !mDescription.isEmpty() )
+    {
+      QDomElement descrElem = doc.createElement( "se:Description" );
+      QDomElement abstractElem = doc.createElement( "se:Abstract" );
+      abstractElem.appendChild( doc.createTextNode( mDescription ) );
+      descrElem.appendChild( abstractElem );
+      ruleElem.appendChild( descrElem );
+    }
+
+    if ( !props.value( "filter", "" ).isEmpty() )
+    {
+      QDomElement filterElem = doc.createElement( "ogc:Filter" );
+      QgsSymbolLayerV2Utils::createFunctionElement( doc, filterElem, props.value( "filter", "" ) );
+      ruleElem.appendChild( filterElem );
+    }
+
+    if ( !props.value( "scaleMinDenom", "" ).isEmpty() )
+    {
+      QDomElement scaleMinDenomElem = doc.createElement( "se:MinScaleDenominator" );
+      scaleMinDenomElem.appendChild( doc.createTextNode( props.value( "scaleMinDenom", "" ) ) );
+      ruleElem.appendChild( scaleMinDenomElem );
+    }
+
+    if ( !props.value( "scaleMaxDenom", "" ).isEmpty() )
+    {
+      QDomElement scaleMaxDenomElem = doc.createElement( "se:MaxScaleDenominator" );
+      scaleMaxDenomElem.appendChild( doc.createTextNode( props.value( "scaleMaxDenom", "" ) ) );
+      ruleElem.appendChild( scaleMaxDenomElem );
+    }
+
+    mSymbol->toSld( doc, ruleElem, props );
+  }
+
+  // loop into childern rule list
+  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
+  {
+    ( *it )->toSld( doc, element, props );
+  }
+}
+
 bool QgsRuleBasedRendererV2::Rule::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
 {
   mActiveChildren.clear();
@@ -377,6 +459,119 @@ QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::create( QDomElement&
   return rule;
 }
 
+QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::createFromSld( QDomElement& ruleElem, QGis::GeometryType geomType )
+{
+  if ( ruleElem.localName() != "Rule" )
+  {
+    QgsDebugMsg( QString( "invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
+    return NULL;
+  }
+
+  QString label, description, filterExp;
+  int scaleMinDenom = 0, scaleMaxDenom = 0;
+  QgsSymbolLayerV2List layers;
+
+  // retrieve the Rule element child nodes
+  QDomElement childElem = ruleElem.firstChildElement();
+  while( !childElem.isNull() )
+  {
+    if ( childElem.localName() == "Name" )
+    {
+      label = childElem.firstChild().nodeValue();
+    }
+    else if ( childElem.localName() == "Description" )
+    {
+      // <se:Description> can contains a title and an abstract
+      // prefer Abstract if available
+      QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
+      QDomElement titleElem = childElem.firstChildElement( "Title" );
+      if ( !abstractElem.isNull() )
+      {
+        description = abstractElem.firstChild().nodeValue();
+      }
+      else if ( !titleElem.isNull() && description.isEmpty() )
+      {
+        description = titleElem.firstChild().nodeValue();
+      }
+    }
+    else if ( childElem.localName() == "Abstract" )
+    {
+      // <sld:Abstract>
+      description = childElem.firstChild().nodeValue();
+    }
+    else if ( childElem.localName() == "Title" )
+    {
+      // <sld:Title>
+      if ( description.isEmpty() )
+        description = childElem.firstChild().nodeValue();
+    }
+    else if ( childElem.localName() == "Filter" )
+    {
+      QgsExpression *filter = QgsExpression::createFromOgcFilter( childElem );
+      if ( filter )
+      {
+        if ( filter->hasParserError() )
+        {
+          QgsDebugMsg( "parser error: " + filter->parserErrorString() );
+        }
+        else
+        {
+          filterExp = filter->dump();
+        }
+        delete filter;
+      }
+    }
+    else if ( childElem.localName() == "MinScaleDenominator" )
+    {
+      bool ok;
+      int v = childElem.firstChild().nodeValue().toInt( &ok );
+      if ( ok )
+        scaleMinDenom = v;
+    }
+    else if ( childElem.localName() == "MaxScaleDenominator" )
+    {
+      bool ok;
+      int v = childElem.firstChild().nodeValue().toInt( &ok );
+      if ( ok )
+        scaleMaxDenom = v;
+    }
+    else if ( childElem.localName().endsWith( "Symbolizer" ) )
+    {
+      // create symbol layers for this symbolizer
+      QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
+    }
+
+    childElem = childElem.nextSiblingElement();
+  }
+
+  // now create the symbol
+  QgsSymbolV2 *symbol = 0;
+  if ( layers.size() > 0 )
+  {
+    switch( geomType )
+    {
+      case QGis::Line:
+        symbol = new QgsLineSymbolV2( layers );
+        break;
+
+      case QGis::Polygon:
+        symbol = new QgsFillSymbolV2( layers );
+        break;
+
+      case QGis::Point:
+        symbol = new QgsMarkerSymbolV2( layers );
+        break;
+
+      default:
+        QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
+        return NULL;
+    }
+  }
+
+  // and then create and return the new rule
+  return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
+}
+
 
 /////////////////////
 
@@ -497,6 +692,11 @@ QgsFeatureRendererV2* QgsRuleBasedRendererV2::clone()
   return r;
 }
 
+void QgsRuleBasedRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
+{
+  mRootRule->toSld( doc, element, QgsStringMap() );
+}
+
 // TODO: ideally this function should be removed in favor of legendSymbol(ogy)Items
 QgsSymbolV2List QgsRuleBasedRendererV2::symbols()
 {
@@ -521,7 +721,6 @@ QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
   return rendererElem;
 }
 
-
 QgsLegendSymbologyList QgsRuleBasedRendererV2::legendSymbologyItems( QSize iconSize )
 {
   QgsLegendSymbologyList lst;
@@ -564,6 +763,36 @@ QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element )
   return r;
 }
 
+QgsFeatureRendererV2* QgsRuleBasedRendererV2::createFromSld( QDomElement& element, QGis::GeometryType geomType )
+{
+  // retrieve child rules
+  Rule* root = 0;
+
+  QDomElement ruleElem = element.firstChildElement( "Rule" );
+  while ( !ruleElem.isNull() )
+  {
+    Rule *child = Rule::createFromSld( ruleElem, geomType );
+    if ( child )
+    {
+      // create the root rule if not done before
+      if ( !root )
+        root = new Rule( 0 );
+
+      root->appendChild( child );
+    }
+
+    ruleElem = ruleElem.nextSiblingElement( "Rule" );
+  }
+
+  if ( !root )
+  {
+    // no valid rules was found
+    return NULL;
+  }
+
+  // create and return the new renderer
+  return new QgsRuleBasedRendererV2( root );
+}
 
 #include "qgscategorizedsymbolrendererv2.h"
 #include "qgsgraduatedsymbolrendererv2.h"
diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.h b/src/core/symbology-ng/qgsrulebasedrendererv2.h
index 6a773ed..c35c013 100644
--- a/src/core/symbology-ng/qgsrulebasedrendererv2.h
+++ b/src/core/symbology-ng/qgsrulebasedrendererv2.h
@@ -18,6 +18,7 @@
 
 #include "qgsfield.h"
 #include "qgsfeature.h"
+#include "qgis.h"
 
 #include "qgsrendererv2.h"
 
@@ -116,6 +117,9 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
         //! clone this rule, return new instance
         Rule* clone() const;
 
+        void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props );
+        static Rule* createFromSld( QDomElement& element, QGis::GeometryType geomType );
+
         QDomElement save( QDomDocument& doc, QgsSymbolV2Map& symbolMap );
 
         //! prepare the rule for rendering and its children (build active children array)
@@ -197,6 +201,10 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
 
     virtual QgsFeatureRendererV2* clone();
 
+    virtual void toSld( QDomDocument& doc, QDomElement &element ) const;
+
+    static QgsFeatureRendererV2* createFromSld( QDomElement& element, QGis::GeometryType geomType );
+
     virtual QgsSymbolV2List symbols();
 
     //! store renderer info to XML element
diff --git a/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp b/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
index 7ebc20c..d302a85 100644
--- a/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
+++ b/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
@@ -7,6 +7,7 @@
 #include "qgslogger.h"
 #include "qgsfeature.h"
 #include "qgsvectorlayer.h"
+#include "qgssymbollayerv2.h"
 
 #include <QDomDocument>
 #include <QDomElement>
@@ -171,6 +172,24 @@ QgsFeatureRendererV2* QgsSingleSymbolRendererV2::clone()
   return r;
 }
 
+void QgsSingleSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
+{
+  QgsStringMap props;
+  if ( !mRotationField.isEmpty() )
+    props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
+  if ( !mSizeScaleField.isEmpty() )
+    props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );
+
+  QDomElement ruleElem = doc.createElement( "se:Rule" );
+  element.appendChild( ruleElem );
+
+  QDomElement nameElem = doc.createElement( "se:Name" );
+  nameElem.appendChild( doc.createTextNode( "Single symbol" ) );
+  ruleElem.appendChild( nameElem );
+
+  mSymbol->toSld( doc, ruleElem, props );
+}
+
 QgsSymbolV2List QgsSingleSymbolRendererV2::symbols()
 {
   QgsSymbolV2List lst;
@@ -206,6 +225,70 @@ QgsFeatureRendererV2* QgsSingleSymbolRendererV2::create( QDomElement& element )
   return r;
 }
 
+QgsFeatureRendererV2* QgsSingleSymbolRendererV2::createFromSld( QDomElement& element, QGis::GeometryType geomType )
+{
+  // XXX this renderer can handle only one Rule!
+
+  // get the first Rule element
+  QDomElement ruleElem = element.firstChildElement( "Rule" );
+  if ( ruleElem.isNull() )
+  {
+    QgsDebugMsg( "no Rule elements found!" );
+    return NULL;
+  }
+
+  QString label, description;
+  QgsSymbolLayerV2List layers;
+
+  // retrieve the Rule element child nodes
+  QDomElement childElem = ruleElem.firstChildElement();
+  while( !childElem.isNull() )
+  {
+    if ( childElem.localName() == "Name" )
+    {
+      label = childElem.firstChild().nodeValue();
+    }
+    else if ( childElem.localName() == "Description" || childElem.localName() == "Abstract" )
+    {
+      description = childElem.firstChild().nodeValue();
+    }
+    else if ( childElem.localName().endsWith( "Symbolizer" ) )
+    {
+      // create symbol layers for this symbolizer
+      QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
+    }
+
+    childElem = childElem.nextSiblingElement();
+  }
+
+  // now create the symbol
+  QgsSymbolV2 *symbol = 0;
+  if ( layers.size() > 0 )
+  {
+    switch( geomType )
+    {
+      case QGis::Line:
+        symbol = new QgsLineSymbolV2( layers );
+        break;
+
+      case QGis::Polygon:
+        symbol = new QgsFillSymbolV2( layers );
+        break;
+
+      case QGis::Point:
+        symbol = new QgsMarkerSymbolV2( layers );
+        break;
+
+      default:
+        QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
+        return NULL;
+    }
+  }
+
+  // and finally return the new renderer
+  return new QgsSingleSymbolRendererV2( symbol );
+}
+
 QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
 {
   QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
diff --git a/src/core/symbology-ng/qgssinglesymbolrendererv2.h b/src/core/symbology-ng/qgssinglesymbolrendererv2.h
index 49052bc..de83591 100644
--- a/src/core/symbology-ng/qgssinglesymbolrendererv2.h
+++ b/src/core/symbology-ng/qgssinglesymbolrendererv2.h
@@ -1,6 +1,7 @@
 #ifndef QGSSINGLESYMBOLRENDERERV2_H
 #define QGSSINGLESYMBOLRENDERERV2_H
 
+#include "qgis.h"
 #include "qgsrendererv2.h"
 
 class CORE_EXPORT QgsSingleSymbolRendererV2 : public QgsFeatureRendererV2
@@ -36,6 +37,9 @@ class CORE_EXPORT QgsSingleSymbolRendererV2 : public QgsFeatureRendererV2
 
     virtual QgsFeatureRendererV2* clone();
 
+    virtual void toSld( QDomDocument& doc, QDomElement &element ) const;
+    static QgsFeatureRendererV2* createFromSld( QDomElement& element, QGis::GeometryType geomType );
+
     //! returns bitwise OR-ed capabilities of the renderer
     //! \note added in 2.0
     virtual int capabilities() { return SymbolLevels | RotationField; }
diff --git a/src/core/symbology-ng/qgssymbollayerv2.cpp b/src/core/symbology-ng/qgssymbollayerv2.cpp
index e936ab7..02ee067 100644
--- a/src/core/symbology-ng/qgssymbollayerv2.cpp
+++ b/src/core/symbology-ng/qgssymbollayerv2.cpp
@@ -93,3 +93,16 @@ void QgsFillSymbolLayerV2::_renderPolygon( QPainter* p, const QPolygonF& points,
     p->drawPath( path );
   }
 }
+
+void QgsMarkerSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
+  if ( !props.value( "uom", "" ).isEmpty() )
+    symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
+  element.appendChild( symbolizerElem );
+
+  // <Geometry>
+  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
+
+  writeSldMarker( doc, symbolizerElem, props );
+}
diff --git a/src/core/symbology-ng/qgssymbollayerv2.h b/src/core/symbology-ng/qgssymbollayerv2.h
index 0c798b9..400d479 100644
--- a/src/core/symbology-ng/qgssymbollayerv2.h
+++ b/src/core/symbology-ng/qgssymbollayerv2.h
@@ -7,6 +7,8 @@
 #include <QMap>
 #include <QPointF>
 #include <QSet>
+#include <QDomDocument>
+#include <QDomElement>
 
 #include "qgssymbolv2.h"
 
@@ -17,8 +19,6 @@ class QSize;
 class QPolygonF;
 
 class QgsRenderContext;
-class QgsSymbolV2;
-
 
 class CORE_EXPORT QgsSymbolLayerV2
 {
@@ -37,6 +37,9 @@ class CORE_EXPORT QgsSymbolLayerV2
 
     virtual QgsSymbolLayerV2* clone() const = 0;
 
+    virtual void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+    { Q_UNUSED( props ); element.appendChild( doc.createComment( QString( "SymbolLayerV2 %1 not implemented yet" ).arg( layerType() ) ) ); }
+
     virtual QgsStringMap properties() const = 0;
 
     virtual void drawPreviewIcon( QgsSymbolV2RenderContext& context, QSize size ) = 0;
@@ -91,6 +94,11 @@ class CORE_EXPORT QgsMarkerSymbolLayerV2 : public QgsSymbolLayerV2
     void setOffset( QPointF offset ) { mOffset = offset; }
     QPointF offset() { return mOffset; }
 
+    virtual void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
+    virtual void writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+    { Q_UNUSED( props ); element.appendChild( doc.createComment( QString( "QgsMarkerSymbolLayerV2 %1 not implemented yet" ).arg( layerType() ) ) ); }
+
   protected:
     QgsMarkerSymbolLayerV2( bool locked = false );
 
diff --git a/src/core/symbology-ng/qgssymbollayerv2registry.cpp b/src/core/symbology-ng/qgssymbollayerv2registry.cpp
index 8c07b39..91eb517 100644
--- a/src/core/symbology-ng/qgssymbollayerv2registry.cpp
+++ b/src/core/symbology-ng/qgssymbollayerv2registry.cpp
@@ -13,33 +13,33 @@ QgsSymbolLayerV2Registry::QgsSymbolLayerV2Registry()
 {
   // init registry with known symbol layers
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "SimpleLine", QObject::tr( "Simple line" ), QgsSymbolV2::Line,
-                      QgsSimpleLineSymbolLayerV2::create ) );
+                      QgsSimpleLineSymbolLayerV2::create, QgsSimpleLineSymbolLayerV2::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "MarkerLine", QObject::tr( "Marker line" ), QgsSymbolV2::Line,
-                      QgsMarkerLineSymbolLayerV2::create ) );
+                      QgsMarkerLineSymbolLayerV2::create, QgsMarkerLineSymbolLayerV2::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "LineDecoration", QObject::tr( "Line decoration" ), QgsSymbolV2::Line,
                       QgsLineDecorationSymbolLayerV2::create ) );
 
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "SimpleMarker", QObject::tr( "Simple marker" ), QgsSymbolV2::Marker,
-                      QgsSimpleMarkerSymbolLayerV2::create ) );
+                      QgsSimpleMarkerSymbolLayerV2::create, QgsSimpleMarkerSymbolLayerV2::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "SvgMarker", QObject::tr( "SVG marker" ), QgsSymbolV2::Marker,
-                      QgsSvgMarkerSymbolLayerV2::create ) );
+                      QgsSvgMarkerSymbolLayerV2::create, QgsSvgMarkerSymbolLayerV2::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "FontMarker", QObject::tr( "Font marker" ), QgsSymbolV2::Marker,
-                      QgsFontMarkerSymbolLayerV2::create ) );
+                      QgsFontMarkerSymbolLayerV2::create, QgsFontMarkerSymbolLayerV2::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "EllipseMarker", QObject::tr( "Ellipse marker" ), QgsSymbolV2::Marker,
-                      QgsEllipseSymbolLayerV2::create ) );
+                      QgsEllipseSymbolLayerV2::create, QgsEllipseSymbolLayerV2::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "VectorField", QObject::tr( "Vector Field marker" ), QgsSymbolV2::Marker,
                       QgsVectorFieldSymbolLayer::create ) );
 
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "SimpleFill", QObject::tr( "Simple fill" ), QgsSymbolV2::Fill,
-                      QgsSimpleFillSymbolLayerV2::create ) );
+                      QgsSimpleFillSymbolLayerV2::create, QgsSimpleFillSymbolLayerV2::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "SVGFill", QObject::tr( "SVG fill" ), QgsSymbolV2::Fill,
-                      QgsSVGFillSymbolLayer::create ) );
+                      QgsSVGFillSymbolLayer::create, QgsSVGFillSymbolLayer::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "CentroidFill", QObject::tr( "Centroid fill" ), QgsSymbolV2::Fill,
-                      QgsCentroidFillSymbolLayerV2::create ) );
+                      QgsCentroidFillSymbolLayerV2::create, QgsCentroidFillSymbolLayerV2::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "LinePatternFill", QObject::tr( "Line pattern fill" ), QgsSymbolV2::Fill,
-                      QgsLinePatternFillSymbolLayer::create ) );
+                      QgsLinePatternFillSymbolLayer::create, QgsLinePatternFillSymbolLayer::createFromSld ) );
   addSymbolLayerType( new QgsSymbolLayerV2Metadata( "PointPatternFill", QObject::tr( "Point pattern fill" ), QgsSymbolV2::Fill,
-                      QgsPointPatternFillSymbolLayer::create ) );
+                      QgsPointPatternFillSymbolLayer::create, QgsPointPatternFillSymbolLayer::createFromSld ) );
 }
 
 QgsSymbolLayerV2Registry::~QgsSymbolLayerV2Registry()
@@ -101,6 +101,14 @@ QgsSymbolLayerV2* QgsSymbolLayerV2Registry::createSymbolLayer( QString name, con
   return mMetadata[name]->createSymbolLayer( properties );
 }
 
+QgsSymbolLayerV2* QgsSymbolLayerV2Registry::createSymbolLayerFromSld( QString name, QDomElement& element ) const
+{
+  if ( !mMetadata.contains( name ) )
+    return NULL;
+
+  return mMetadata[name]->createSymbolLayerFromSld( element );
+}
+
 QStringList QgsSymbolLayerV2Registry::symbolLayersForType( QgsSymbolV2::SymbolType type )
 {
   QStringList lst;
diff --git a/src/core/symbology-ng/qgssymbollayerv2registry.h b/src/core/symbology-ng/qgssymbollayerv2registry.h
index d3e7a8a..5217186 100644
--- a/src/core/symbology-ng/qgssymbollayerv2registry.h
+++ b/src/core/symbology-ng/qgssymbollayerv2registry.h
@@ -27,6 +27,9 @@ class CORE_EXPORT QgsSymbolLayerV2AbstractMetadata
     virtual QgsSymbolLayerV2* createSymbolLayer( const QgsStringMap& map ) = 0;
     /** create widget for symbol layer of this type. Can return NULL if there's no GUI */
     virtual QgsSymbolLayerV2Widget* createSymbolLayerWidget( const QgsVectorLayer * ) { return NULL; }
+    /** create a symbol layer of this type given the map of properties. */
+    virtual QgsSymbolLayerV2* createSymbolLayerFromSld( QDomElement & ) { return NULL; }
+
 
   protected:
     QString mName;
@@ -36,6 +39,7 @@ class CORE_EXPORT QgsSymbolLayerV2AbstractMetadata
 
 typedef QgsSymbolLayerV2*( *QgsSymbolLayerV2CreateFunc )( const QgsStringMap& );
 typedef QgsSymbolLayerV2Widget*( *QgsSymbolLayerV2WidgetFunc )( const QgsVectorLayer* );
+typedef QgsSymbolLayerV2*( *QgsSymbolLayerV2CreateFromSldFunc )( QDomElement& );
 
 /**
  Convenience metadata class that uses static functions to create symbol layer and its widget.
@@ -47,19 +51,31 @@ class CORE_EXPORT QgsSymbolLayerV2Metadata : public QgsSymbolLayerV2AbstractMeta
                               QgsSymbolV2::SymbolType type,
                               QgsSymbolLayerV2CreateFunc pfCreate,
                               QgsSymbolLayerV2WidgetFunc pfWidget = NULL )
-        : QgsSymbolLayerV2AbstractMetadata( name, visibleName, type ), mCreateFunc( pfCreate ), mWidgetFunc( pfWidget ) {}
+        : QgsSymbolLayerV2AbstractMetadata( name, visibleName, type ),
+          mCreateFunc( pfCreate ), mWidgetFunc( pfWidget ), mCreateFromSldFunc( NULL ) {}
+
+    QgsSymbolLayerV2Metadata( QString name, QString visibleName,
+                              QgsSymbolV2::SymbolType type,
+                              QgsSymbolLayerV2CreateFunc pfCreate,
+                              QgsSymbolLayerV2CreateFromSldFunc pfCreateFromSld,
+                              QgsSymbolLayerV2WidgetFunc pfWidget = NULL )
+        : QgsSymbolLayerV2AbstractMetadata( name, visibleName, type ),
+          mCreateFunc( pfCreate ), mWidgetFunc ( pfWidget ), mCreateFromSldFunc( pfCreateFromSld ) {}
 
     QgsSymbolLayerV2CreateFunc createFunction() const { return mCreateFunc; }
     QgsSymbolLayerV2WidgetFunc widgetFunction() const { return mWidgetFunc; }
+    QgsSymbolLayerV2CreateFromSldFunc createFromSldFunction() const { return mCreateFromSldFunc; }
 
     void setWidgetFunction( QgsSymbolLayerV2WidgetFunc f ) { mWidgetFunc = f; }
 
     virtual QgsSymbolLayerV2* createSymbolLayer( const QgsStringMap& map ) { return mCreateFunc ? mCreateFunc( map ) : NULL; }
     virtual QgsSymbolLayerV2Widget* createSymbolLayerWidget( const QgsVectorLayer* vl ) { return mWidgetFunc ? mWidgetFunc( vl ) : NULL; }
+    virtual QgsSymbolLayerV2* createSymbolLayerFromSld( QDomElement& elem ) { return mCreateFromSldFunc ? mCreateFromSldFunc( elem ) : NULL; }
 
   protected:
     QgsSymbolLayerV2CreateFunc mCreateFunc;
     QgsSymbolLayerV2WidgetFunc mWidgetFunc;
+    QgsSymbolLayerV2CreateFromSldFunc mCreateFromSldFunc;
 };
 
 
@@ -83,6 +99,9 @@ class CORE_EXPORT QgsSymbolLayerV2Registry
     //! create a new instance of symbol layer given symbol layer name and properties
     QgsSymbolLayerV2* createSymbolLayer( QString name, const QgsStringMap& properties = QgsStringMap() ) const;
 
+    //! create a new instance of symbol layer given symbol layer name and SLD
+    QgsSymbolLayerV2* createSymbolLayerFromSld( QString name, QDomElement &element ) const;
+
     //! return a list of available symbol layers for a specified symbol type
     QStringList symbolLayersForType( QgsSymbolV2::SymbolType type );
 
diff --git a/src/core/symbology-ng/qgssymbollayerv2utils.cpp b/src/core/symbology-ng/qgssymbollayerv2utils.cpp
index b8ab5bd..f6da224 100644
--- a/src/core/symbology-ng/qgssymbollayerv2utils.cpp
+++ b/src/core/symbology-ng/qgssymbollayerv2utils.cpp
@@ -5,11 +5,14 @@
 #include "qgssymbollayerv2registry.h"
 #include "qgssymbolv2.h"
 #include "qgsvectorcolorrampv2.h"
+#include "qgsexpression.h"
 
 #include "qgslogger.h"
 #include "qgsrendercontext.h"
 
 #include <QColor>
+#include <QFont>
+#include <QDomDocument>
 #include <QDomNode>
 #include <QDomElement>
 #include <QIcon>
@@ -39,6 +42,66 @@ QColor QgsSymbolLayerV2Utils::decodeColor( QString str )
   return QColor( red, green, blue, alpha );
 }
 
+QString QgsSymbolLayerV2Utils::encodeSldAlpha( int alpha )
+{
+  return QString::number( alpha / 255.0, 'f', 2 );
+}
+
+int QgsSymbolLayerV2Utils::decodeSldAlpha( QString str )
+{
+  bool ok;
+  double alpha = str.toDouble( &ok );
+  if ( !ok || alpha > 1 )
+    alpha = 255;
+  else if ( alpha < 0 )
+    alpha = 0;
+  return alpha * 255;
+}
+
+QString QgsSymbolLayerV2Utils::encodeSldFontStyle( QFont::Style style )
+{
+  switch ( style )
+  {
+    case QFont::StyleNormal:  return "normal";
+    case QFont::StyleItalic:  return "italic";
+    case QFont::StyleOblique: return "oblique";
+    default: return "";
+  }
+}
+
+QFont::Style QgsSymbolLayerV2Utils::decodeSldFontStyle( QString str )
+{
+  if ( str == "normal" ) return QFont::StyleNormal;
+  if ( str == "italic" ) return QFont::StyleItalic;
+  if ( str == "oblique" ) return QFont::StyleOblique;
+  return QFont::StyleNormal;
+}
+
+QString QgsSymbolLayerV2Utils::encodeSldFontWeight( int weight )
+{
+  if ( weight == 50 ) return "normal";
+  if ( weight == 75 ) return "bold";
+
+  // QFont::Weight is between 0 and 99
+  // CSS font-weight is between 100 and 900
+  if ( weight < 0 ) return "100";
+  if ( weight > 99 ) return "900";
+  return QString::number( weight * 800 / 99 + 100 );
+}
+
+int QgsSymbolLayerV2Utils::decodeSldFontWeight( QString str )
+{
+  bool ok;
+  int weight = str.toInt( &ok );
+  if ( !ok ) return ( int ) QFont::Normal;
+
+  // CSS font-weight is between 100 and 900
+  // QFont::Weight is between 0 and 99
+  if ( weight > 900 ) return 99;
+  if ( weight < 100 ) return 0;
+  return ( weight - 100 ) * 99 / 800;
+}
+
 QString QgsSymbolLayerV2Utils::encodePenStyle( Qt::PenStyle style )
 {
   switch ( style )
@@ -83,6 +146,25 @@ Qt::PenJoinStyle QgsSymbolLayerV2Utils::decodePenJoinStyle( QString str )
   return Qt::BevelJoin;
 }
 
+QString QgsSymbolLayerV2Utils::encodeSldLineJoinStyle( Qt::PenJoinStyle style )
+{
+  switch ( style )
+  {
+    case Qt::BevelJoin: return "bevel";
+    case Qt::MiterJoin: return "mitre";
+    case Qt::RoundJoin: return "round";
+    default: return "";
+  }
+}
+
+Qt::PenJoinStyle QgsSymbolLayerV2Utils::decodeSldLineJoinStyle( QString str )
+{
+  if ( str == "bevel" ) return Qt::BevelJoin;
+  if ( str == "mitre" ) return Qt::MiterJoin;
+  if ( str == "round" ) return Qt::RoundJoin;
+  return Qt::BevelJoin;
+}
+
 QString QgsSymbolLayerV2Utils::encodePenCapStyle( Qt::PenCapStyle style )
 {
   switch ( style )
@@ -102,6 +184,24 @@ Qt::PenCapStyle QgsSymbolLayerV2Utils::decodePenCapStyle( QString str )
   return Qt::SquareCap;
 }
 
+QString QgsSymbolLayerV2Utils::encodeSldLineCapStyle( Qt::PenCapStyle style )
+{
+  switch ( style )
+  {
+    case Qt::SquareCap: return "square";
+    case Qt::FlatCap:   return "butt";
+    case Qt::RoundCap:  return "round";
+    default: return "";
+  }
+}
+
+Qt::PenCapStyle QgsSymbolLayerV2Utils::decodeSldLineCapStyle( QString str )
+{
+  if ( str == "square" ) return Qt::SquareCap;
+  if ( str == "butt" ) return Qt::FlatCap;
+  if ( str == "round" ) return Qt::RoundCap;
+  return Qt::SquareCap;
+}
 
 QString QgsSymbolLayerV2Utils::encodeBrushStyle( Qt::BrushStyle style )
 {
@@ -146,6 +246,52 @@ Qt::BrushStyle QgsSymbolLayerV2Utils::decodeBrushStyle( QString str )
   return Qt::SolidPattern;
 }
 
+QString QgsSymbolLayerV2Utils::encodeSldBrushStyle( Qt::BrushStyle style )
+{
+  switch( style )
+  {
+    case Qt::CrossPattern: return "cross";
+    case Qt::DiagCrossPattern: return "x";
+
+    /* The following names are taken from the presentation "GeoServer
+     * Cartographic Rendering" by Andrea Aime at the FOSS4G 2010.
+     * (see http://2010.foss4g.org/presentations/3588.pdf)
+     */
+    case Qt::HorPattern: return "horline";
+    case Qt::VerPattern: return "line";
+    case Qt::BDiagPattern: return "slash";
+    case Qt::FDiagPattern: return "backslash";
+
+    /* define the other names following the same pattern used above */
+    case Qt::Dense1Pattern:
+    case Qt::Dense2Pattern:
+    case Qt::Dense3Pattern:
+    case Qt::Dense4Pattern:
+    case Qt::Dense5Pattern:
+    case Qt::Dense6Pattern:
+    case Qt::Dense7Pattern:
+      return QString( "brush://%1" ).arg( encodeBrushStyle( style ) );
+
+    default:
+      return QString();
+  }
+}
+
+Qt::BrushStyle QgsSymbolLayerV2Utils::decodeSldBrushStyle( QString str )
+{
+  if ( str == "horline" ) return Qt::HorPattern;
+  if ( str == "line" ) return Qt::VerPattern;
+  if ( str == "cross" ) return Qt::CrossPattern;
+  if ( str == "slash" ) return Qt::BDiagPattern;
+  if ( str == "backshash" ) return Qt::FDiagPattern;
+  if ( str == "x" ) return Qt::DiagCrossPattern;
+
+  if ( str.startsWith( "brush://" ) )
+    return decodeBrushStyle( str.mid( 8 ) );
+
+  return Qt::NoBrush;
+}
+
 QString QgsSymbolLayerV2Utils::encodePoint( QPointF point )
 {
   return QString( "%1,%2" ).arg( point.x() ).arg( point.y() );
@@ -187,6 +333,49 @@ QgsSymbolV2::OutputUnit QgsSymbolLayerV2Utils::decodeOutputUnit( QString str )
   return QgsSymbolV2::MM;
 }
 
+QString QgsSymbolLayerV2Utils::encodeSldUom( QgsSymbolV2::OutputUnit unit, double *scaleFactor )
+{
+  switch ( unit )
+  {
+    case QgsSymbolV2::MapUnit:
+      if ( scaleFactor )
+        *scaleFactor = 0.001; // from millimeters to meters
+      return "http://www.opengeospatial.org/se/units/metre";
+
+    case QgsSymbolV2::MM:
+    default:
+      // pixel is the SLD default uom. The "standardized rendering pixel
+      // size" is defined to be 0.28mm × 0.28mm (millimeters).
+      if ( scaleFactor )
+        *scaleFactor = 0.28;  // from millimeters to pixels
+
+      // http://www.opengeospatial.org/sld/units/pixel
+      return QString();
+  }
+}
+
+QgsSymbolV2::OutputUnit QgsSymbolLayerV2Utils::decodeSldUom( QString str, double *scaleFactor )
+{
+  if ( str == "http://www.opengeospatial.org/se/units/metre" )
+  {
+    if ( scaleFactor )
+      *scaleFactor = 1000.0;  // from meters to millimeters
+    return QgsSymbolV2::MapUnit;
+  }
+  else if ( str == "http://www.opengeospatial.org/se/units/foot" )
+  {
+    if ( scaleFactor )
+      *scaleFactor = 304.8; // from feet to meters
+    return QgsSymbolV2::MapUnit;
+  }
+
+  // pixel is the SLD default uom. The "standardized rendering pixel
+  // size" is defined to be 0.28mm x 0.28mm (millimeters).
+  if ( scaleFactor )
+    *scaleFactor = 1/0.00028; // from pixels to millimeters
+  return QgsSymbolV2::MM;
+}
+
 QString QgsSymbolLayerV2Utils::encodeRealVector( const QVector<qreal>& v )
 {
   QString vectorString;
@@ -216,6 +405,35 @@ QVector<qreal> QgsSymbolLayerV2Utils::decodeRealVector( const QString& s )
   return resultVector;
 }
 
+QString QgsSymbolLayerV2Utils::encodeSldRealVector( const QVector<qreal>& v )
+{
+  QString vectorString;
+  QVector<qreal>::const_iterator it = v.constBegin();
+  for ( ; it != v.constEnd(); ++it )
+  {
+    if ( it != v.constBegin() )
+    {
+      vectorString.append( " " );
+    }
+    vectorString.append( QString::number( *it ) );
+  }
+  return vectorString;
+}
+
+QVector<qreal> QgsSymbolLayerV2Utils::decodeSldRealVector( const QString& s )
+{
+  QVector<qreal> resultVector;
+
+  QStringList realList = s.split( " " );
+  QStringList::const_iterator it = realList.constBegin();
+  for ( ; it != realList.constEnd(); ++it )
+  {
+    resultVector.append( it->toDouble() );
+  }
+
+  return resultVector;
+}
+
 QIcon QgsSymbolLayerV2Utils::symbolPreviewIcon( QgsSymbolV2* symbol, QSize size )
 {
   return QIcon( symbolPreviewPixmap( symbol, size ) );
@@ -506,6 +724,1412 @@ QDomElement QgsSymbolLayerV2Utils::saveSymbol( QString name, QgsSymbolV2* symbol
 }
 
 
+bool QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( QDomElement& element,
+                                                            QGis::GeometryType geomType,
+                                                            QgsSymbolLayerV2List &layers )
+{
+  QgsDebugMsg( "Entered." );
+
+  if ( element.isNull() )
+    return false;
+
+  QgsSymbolLayerV2 *l = 0;
+
+  QString symbolizerName = element.localName();
+
+  if ( symbolizerName == "PointSymbolizer" )
+  {
+    // first check for Graphic element, nothing will be rendered if not found
+    QDomElement graphicElem = element.firstChildElement( "Graphic" );
+    if ( graphicElem.isNull() )
+    {
+      QgsDebugMsg( "Graphic element not found in PointSymbolizer" );
+    }
+    else
+    {
+      switch( geomType )
+      {
+        case QGis::Polygon:
+          // polygon layer and point symbolizer: draw poligon centroid
+          l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "CentroidFill", element );
+          if ( l )
+            layers.append( l );
+
+          break;
+
+        case QGis::Point:
+          // point layer and point symbolizer: use markers
+          l = createMarkerLayerFromSld( element );
+          if ( l )
+            layers.append( l );
+
+          break;
+
+        case QGis::Line:
+          // line layer and point symbolizer: draw central point
+          l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleMarker", element );
+          if ( l )
+            layers.append( l );
+
+          break;
+
+        default:
+          break;
+      }
+    }
+  }
+
+  if ( symbolizerName == "LineSymbolizer" )
+  {
+    // check for Stroke element, nothing will be rendered if not found
+    QDomElement strokeElem = element.firstChildElement( "Stroke" );
+    if ( strokeElem.isNull() )
+    {
+      QgsDebugMsg( "Stroke element not found in LineSymbolizer" );
+    }
+    else
+    {
+      switch( geomType )
+      {
+        case QGis::Polygon:
+        case QGis::Line:
+          // polygon layer and line symbolizer: draw polygon outline
+          // line layer and line symbolizer: draw line
+          l = createLineLayerFromSld( element );
+          if ( l )
+            layers.append( l );
+
+          break;
+
+        case QGis::Point:
+          // point layer and line symbolizer: draw a little line marker
+          l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "MarkerLine", element );
+          if ( l )
+            layers.append( l );
+
+        default:
+          break;
+      }
+    }
+  }
+
+  if ( symbolizerName == "PolygonSymbolizer" )
+  {
+    // get Fill and Stroke elements, nothing will be rendered if both are missing
+    QDomElement fillElem = element.firstChildElement( "Fill" );
+    QDomElement strokeElem = element.firstChildElement( "Stroke" );
+    if ( fillElem.isNull() && strokeElem.isNull() )
+    {
+      QgsDebugMsg( "neither Fill nor Stroke element not found in PolygonSymbolizer" );
+    }
+    else
+    {
+      QgsSymbolLayerV2 *l = 0;
+
+      switch( geomType )
+      {
+        case QGis::Polygon:
+          // polygon layer and polygon symbolizer: draw fill
+
+          l = createFillLayerFromSld( element );
+          if ( l )
+          {
+            layers.append( l );
+
+            // SVGFill and SimpleFill symbolLayerV2 supports outline internally,
+            // so don't go forward to create a different symbolLayerV2 for outline
+            if ( l->layerType() == "SimpleFill" || l->layerType() == "SVGFill" )
+              break;
+          }
+
+          // now create polygon outline
+          // polygon layer and polygon symbolizer: draw polygon outline
+          l = createLineLayerFromSld( element );
+          if ( l )
+            layers.append( l );
+
+          break;
+
+        case QGis::Line:
+          // line layer and polygon symbolizer: draw line
+          l = createLineLayerFromSld( element );
+          if ( l )
+            layers.append( l );
+
+          break;
+
+        case QGis::Point:
+          // point layer and polygon symbolizer: draw a square marker
+          convertPolygonSymbolizerToPointMarker( element, layers );
+          break;
+
+        default:
+          break;
+      }
+    }
+  }
+
+  return true;
+}
+
+QgsSymbolLayerV2* QgsSymbolLayerV2Utils::createFillLayerFromSld( QDomElement &element )
+{
+  QDomElement fillElem = element.firstChildElement( "Fill" );
+  if ( fillElem.isNull() )
+  {
+    QgsDebugMsg( "Fill element not found" );
+    return NULL;
+  }
+
+  QgsSymbolLayerV2 *l = 0;
+
+  if ( needLinePatternFill( element ) )
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "LinePatternFill", element );
+  else if ( needPointPatternFill( element ) )
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "PointPatternFill", element );
+  else if ( needSvgFill( element ) )
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SVGFill", element );
+  else
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleFill", element );
+
+  return l;
+}
+
+QgsSymbolLayerV2* QgsSymbolLayerV2Utils::createLineLayerFromSld( QDomElement &element )
+{
+  QDomElement strokeElem = element.firstChildElement( "Stroke" );
+  if ( strokeElem.isNull() )
+  {
+    QgsDebugMsg( "Stroke element not found" );
+    return NULL;
+  }
+
+  QgsSymbolLayerV2 *l = 0;
+
+  if ( needMarkerLine( element ) )
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "MarkerLine", element );
+  else
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleLine", element );
+
+  return l;
+}
+
+QgsSymbolLayerV2* QgsSymbolLayerV2Utils::createMarkerLayerFromSld( QDomElement &element )
+{
+  QDomElement graphicElem = element.firstChildElement( "Graphic" );
+  if ( graphicElem.isNull() )
+  {
+    QgsDebugMsg( "Graphic element not found" );
+    return NULL;
+  }
+
+  QgsSymbolLayerV2 *l = 0;
+
+  if ( needFontMarker( element ) )
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "FontMarker", element );
+  else if ( needSvgMarker( element ) )
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SvgMarker", element );
+  else if ( needEllipseMarker( element ) )
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "EllipseMarker", element );
+  else
+    l = QgsSymbolLayerV2Registry::instance()->createSymbolLayerFromSld( "SimpleMarker", element );
+
+  return l;
+}
+
+bool QgsSymbolLayerV2Utils::hasExternalGraphic( QDomElement &element )
+{
+  QDomElement graphicElem = element.firstChildElement( "Graphic" );
+  if( graphicElem.isNull() )
+    return false;
+
+  QDomElement externalGraphicElem = graphicElem.firstChildElement( "ExternalGraphic" );
+  if ( externalGraphicElem.isNull() )
+    return false;
+
+  // check for format
+  QDomElement formatElem = externalGraphicElem.firstChildElement( "Format" );
+  if ( formatElem.isNull() )
+    return false;
+
+  QString format = formatElem.firstChild().nodeValue();
+  if ( format != "image/svg+xml" )
+  {
+    QgsDebugMsg( "unsupported External Graphic format found: " + format );
+    return false;
+  }
+
+  // check for a valid content
+  QDomElement onlineResourceElem = externalGraphicElem.firstChildElement( "OnlineResource" );
+  QDomElement inlineContentElem = externalGraphicElem.firstChildElement( "InlineContent" );
+  if ( !onlineResourceElem.isNull() )
+  {
+    return true;
+  }
+  else if ( !inlineContentElem.isNull() )
+  {
+    return false; // not implemented yet
+  }
+  else
+  {
+    return false;
+  }
+
+  return false;
+}
+
+bool QgsSymbolLayerV2Utils::hasWellKnownMark( QDomElement &element )
+{
+  QDomElement graphicElem = element.firstChildElement( "Graphic" );
+  if( graphicElem.isNull() )
+    return false;
+
+  QDomElement markElem = graphicElem.firstChildElement( "Mark" );
+  if ( markElem.isNull() )
+    return false;
+
+  QDomElement wellKnownNameElem = markElem.firstChildElement( "WellKnownName" );
+  if ( wellKnownNameElem.isNull() )
+    return false;
+
+  return true;
+}
+
+
+bool QgsSymbolLayerV2Utils::needFontMarker( QDomElement &element )
+{
+  QDomElement graphicElem = element.firstChildElement( "Graphic" );
+  if( graphicElem.isNull() )
+    return false;
+
+  QDomElement markElem = graphicElem.firstChildElement( "Mark" );
+  if ( markElem.isNull() )
+    return false;
+
+  // check for format
+  QDomElement formatElem = markElem.firstChildElement( "Format" );
+  if ( formatElem.isNull() )
+    return false;
+
+  QString format = formatElem.firstChild().nodeValue();
+  if ( format != "ttf" )
+  {
+    QgsDebugMsg( "unsupported Graphic Mark format found: " + format );
+    return false;
+  }
+
+  // check for a valid content
+  QDomElement onlineResourceElem = markElem.firstChildElement( "OnlineResource" );
+  QDomElement inlineContentElem = markElem.firstChildElement( "InlineContent" );
+  if ( !onlineResourceElem.isNull() )
+  {
+    // mark with ttf format has a markIndex element
+    QDomElement markIndexElem = markElem.firstChildElement( "MarkIndex" );
+    if ( !markIndexElem.isNull() )
+      return true;
+  }
+  else if ( !inlineContentElem.isNull() )
+  {
+    return false; // not implemented yet
+  }
+
+  return false;
+}
+
+bool QgsSymbolLayerV2Utils::needSvgMarker( QDomElement &element )
+{
+  return hasExternalGraphic( element );
+}
+
+bool QgsSymbolLayerV2Utils::needEllipseMarker( QDomElement &element )
+{
+  QDomElement graphicElem = element.firstChildElement( "Graphic" );
+  if( graphicElem.isNull() )
+    return false;
+
+  QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
+  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
+  {
+    if ( it.key() == "widthHeightFactor" )
+    {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool QgsSymbolLayerV2Utils::needMarkerLine( QDomElement &element )
+{
+  QDomElement strokeElem = element.firstChildElement( "Stroke" );
+  if( strokeElem.isNull() )
+    return false;
+
+  QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
+  if ( graphicStrokeElem.isNull() )
+    return false;
+
+  return hasWellKnownMark( graphicStrokeElem );
+}
+
+bool QgsSymbolLayerV2Utils::needLinePatternFill( QDomElement &element ) { Q_UNUSED( element ); return false; }
+bool QgsSymbolLayerV2Utils::needPointPatternFill( QDomElement &element ) { Q_UNUSED( element ); return false; }
+
+bool QgsSymbolLayerV2Utils::needSvgFill( QDomElement &element )
+{
+  QDomElement fillElem = element.firstChildElement( "Fill" );
+  if( fillElem.isNull() )
+    return false;
+
+  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
+  if ( graphicFillElem.isNull() )
+    return false;
+
+  return hasExternalGraphic( graphicFillElem );
+}
+
+
+bool QgsSymbolLayerV2Utils::convertPolygonSymbolizerToPointMarker( QDomElement &element, QgsSymbolLayerV2List &layerList )
+{
+  QgsDebugMsg( "Entered." );
+
+  /* SE 1.1 says about PolygonSymbolizer:
+     if a point geometry is referenced instead of a polygon,
+     then a small, square, ortho-normal polygon should be
+     constructed for rendering.
+   */
+
+  QgsSymbolLayerV2List layers;
+
+  // retrieve both Fill and Stroke elements
+  QDomElement fillElem = element.firstChildElement( "Fill" );
+  QDomElement strokeElem = element.firstChildElement( "Stroke" );
+
+  // first symbol layer
+  {
+    bool validFill = false, validBorder = false;
+
+    // check for simple fill
+    // Fill element can contain some SvgParameter elements
+    QColor fillColor;
+    Qt::BrushStyle fillStyle;
+
+    if ( fillFromSld( fillElem, fillStyle, fillColor ) )
+      validFill = true;
+
+    // check for simple outline
+    // Stroke element can contain some SvgParameter elements
+    QColor borderColor;
+    Qt::PenStyle borderStyle;
+    double borderWidth = 1.0, dashOffset = 0.0;
+    QVector<qreal> customDashPattern;
+
+    if ( lineFromSld( strokeElem, borderStyle, borderColor, borderWidth,
+                      0, 0, &customDashPattern, &dashOffset ) )
+      validBorder = true;
+
+    if ( validFill || validBorder )
+    {
+      QgsStringMap map;
+      map["name"] = "square";
+      map["color"] = QgsSymbolLayerV2Utils::encodeColor( validFill ? fillColor : Qt::transparent );
+      map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( validBorder ? borderColor : Qt::transparent );
+      map["size"] = QString::number( 6 );
+      map["angle"] = QString::number( 0 );
+      map["offset"] = QgsSymbolLayerV2Utils::encodePoint( QPointF( 0, 0 ) );
+      layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "SimpleMarker", map ) );
+    }
+  }
+
+  // second symbol layer
+  {
+    bool validFill = false, validBorder = false;
+
+    // check for graphic fill
+    QString name, format;
+    int markIndex = -1;
+    QColor fillColor, borderColor;
+    double borderWidth = 1, size, angle = 0.0;
+    QPointF anchor, offset;
+
+    // Fill element can contain a GraphicFill element
+    QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
+    if ( !graphicFillElem.isNull() )
+    {
+      // GraphicFill element must contain a Graphic element
+      QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
+      if( !graphicElem.isNull() )
+      {
+        // Graphic element can contains some ExternalGraphic and Mark element
+        // search for the first supported one and use it
+        bool found = false;
+
+        QDomElement graphicChildElem = graphicElem.firstChildElement();
+        while ( !graphicChildElem.isNull() )
+        {
+          if ( graphicChildElem.localName() == "Mark" )
+          {
+            // check for a well known name
+            QDomElement wellKnownNameElem = graphicChildElem.firstChildElement( "WellKnownName" );
+            if ( !wellKnownNameElem.isNull() )
+            {
+              name = wellKnownNameElem.firstChild().nodeValue();
+              found = true;
+              break;
+            }
+          }
+
+          if ( graphicChildElem.localName() == "ExternalGraphic" || graphicChildElem.localName() == "Mark" )
+          {
+            // check for external graphic format
+            QDomElement formatElem = graphicChildElem.firstChildElement( "Format" );
+            if ( formatElem.isNull() )
+              continue;
+
+            format = formatElem.firstChild().nodeValue();
+
+            // TODO: remove this check when more formats will be supported
+            // only SVG external graphics are supported in this moment
+            if ( graphicChildElem.localName() == "ExternalGraphic" && format != "image/svg+xml" )
+              continue;
+
+            // TODO: remove this check when more formats will be supported
+            // only ttf marks are supported in this moment
+            if ( graphicChildElem.localName() == "Mark" && format != "ttf" )
+              continue;
+
+            // check for a valid content
+            QDomElement onlineResourceElem = graphicChildElem.firstChildElement( "OnlineResource" );
+            QDomElement inlineContentElem = graphicChildElem.firstChildElement( "InlineContent" );
+
+            if ( !onlineResourceElem.isNull() )
+            {
+              name = onlineResourceElem.attributeNS( "http://www.w3.org/1999/xlink", "href" );
+
+              if ( graphicChildElem.localName() == "Mark" && format == "ttf" )
+              {
+                // mark with ttf format may have a name like ttf://fontFamily
+                if ( name.startsWith( "ttf://" ) )
+                    name = name.mid( 6 );
+
+                // mark with ttf format has a markIndex element
+                QDomElement markIndexElem = graphicChildElem.firstChildElement( "MarkIndex" );
+                if ( markIndexElem.isNull() )
+                  continue;
+
+                bool ok;
+                int v = markIndexElem.firstChild().nodeValue().toInt( &ok );
+                if ( !ok || v < 0 )
+                  continue;
+
+                markIndex = v;
+              }
+
+              found = true;
+              break;
+            }
+            else if ( !inlineContentElem.isNull() )
+              continue; // TODO: not implemeneted yet
+            else
+              continue;
+          }
+
+          // if Mark element is present but it doesn't contains neither
+          // WellKnownName nor OnlineResource nor InlineContent,
+          // use the default mark (square)
+          if ( graphicChildElem.localName() == "Mark" )
+          {
+            name = "square";
+            found = true;
+            break;
+          }
+        }
+
+        // if found a valid Mark, check for its Fill and Stroke element
+        if ( found && graphicChildElem.localName() == "Mark" )
+        {
+          // XXX: recursive definition!?! couldn't be dangerous???
+          // to avoid recursion we handle only simple fill and simple stroke
+
+          // check for simple fill
+          // Fill element can contain some SvgParameter elements
+          Qt::BrushStyle markFillStyle;
+
+          QDomElement markFillElem = graphicChildElem.firstChildElement( "Fill" );
+          if ( fillFromSld( markFillElem, markFillStyle, fillColor ) )
+            validFill = true;
+
+          // check for simple outline
+          // Stroke element can contain some SvgParameter elements
+          Qt::PenStyle borderStyle;
+          double borderWidth = 1.0, dashOffset = 0.0;
+          QVector<qreal> customDashPattern;
+
+          QDomElement markStrokeElem = graphicChildElem.firstChildElement( "Stroke" );
+          if ( lineFromSld( markStrokeElem, borderStyle, borderColor, borderWidth,
+                            0, 0, &customDashPattern, &dashOffset ) )
+            validBorder = true;
+        }
+
+        if ( found )
+        {
+          // check for Opacity, Size, Rotation, AnchorPoint, Displacement
+          QDomElement opacityElem = graphicElem.firstChildElement( "Opacity" );
+          if ( !opacityElem.isNull() )
+            fillColor.setAlpha( decodeSldAlpha( opacityElem.firstChild().nodeValue() ) );
+
+          QDomElement sizeElem = graphicElem.firstChildElement( "Size" );
+          if ( !sizeElem.isNull() )
+          {
+            bool ok;
+            double v = sizeElem.firstChild().nodeValue().toDouble( &ok );
+            if ( ok && v > 0 )
+              size = v;
+          }
+
+          QString angleFunc;
+          if ( rotationFromSldElement( graphicElem, angleFunc ) && !angleFunc.isEmpty() )
+          {
+            bool ok;
+            double v = angleFunc.toDouble( &ok );
+            if ( ok )
+              angle = v;
+          }
+
+          displacementFromSldElement( graphicElem, offset );
+        }
+      }
+    }
+
+    if ( validFill || validBorder )
+    {
+      if ( format == "image/svg+xml" )
+      {
+        QgsStringMap map;
+        map["name"] = name;
+        map["fill"] = fillColor.name();
+        map["outline"] = borderColor.name();
+        map["outline-width"] = QString::number( borderWidth );
+        if ( size > 0 )
+          map["size"] = QString::number( size );
+        if ( !doubleNear( angle, 0.0 ) )
+          map["angle"] = QString::number( angle );
+        if ( !offset.isNull() )
+          map["offset"] = QgsSymbolLayerV2Utils::encodePoint( offset );
+        layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "SvgMarker", map ) );
+      }
+      else if ( format == "ttf" )
+      {
+        QgsStringMap map;
+        map["font"] = name;
+        map["chr"] = markIndex;
+        map["color"] = QgsSymbolLayerV2Utils::encodeColor( validFill ? fillColor : Qt::transparent );
+        if ( size > 0 )
+          map["size"] = QString::number( size );
+        if ( !doubleNear( angle, 0.0 ) )
+          map["angle"] = QString::number( angle );
+        if ( !offset.isNull() )
+          map["offset"] = QgsSymbolLayerV2Utils::encodePoint( offset );
+        layers.append( QgsSymbolLayerV2Registry::instance()->createSymbolLayer( "FontMarker", map ) );
+      }
+    }
+  }
+
+  if ( layers.isEmpty() )
+    return false;
+
+  layerList << layers;
+  layers.clear();
+  return true;
+}
+
+void QgsSymbolLayerV2Utils::fillToSld( QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, QColor color )
+{
+  QString patternName;
+  switch ( brushStyle )
+  {
+    case Qt::NoBrush:
+      return;
+
+    case Qt::SolidPattern:
+      if ( color.isValid() )
+      {
+        element.appendChild( createSvgParameterElement( doc, "fill", color.name() ) );
+        if ( color.alpha() < 255 )
+          element.appendChild( createSvgParameterElement( doc, "fill-opacity", encodeSldAlpha( color.alpha() ) ) );
+      }
+      return;
+
+    case Qt::CrossPattern:
+    case Qt::DiagCrossPattern:
+    case Qt::HorPattern:
+    case Qt::VerPattern:
+    case Qt::BDiagPattern:
+    case Qt::FDiagPattern:
+    case Qt::Dense1Pattern:
+    case Qt::Dense2Pattern:
+    case Qt::Dense3Pattern:
+    case Qt::Dense4Pattern:
+    case Qt::Dense5Pattern:
+    case Qt::Dense6Pattern:
+    case Qt::Dense7Pattern:
+      patternName = encodeSldBrushStyle( brushStyle );
+      break;
+
+    default:
+      element.appendChild( doc.createComment( QString( "Qt::BrushStyle '%1'' not supported yet" ).arg( brushStyle ) ) );
+      return;
+  }
+
+  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
+  element.appendChild( graphicFillElem );
+
+  QDomElement graphicElem = doc.createElement( "se:Graphic" );
+  graphicFillElem.appendChild( graphicElem );
+
+  QColor fillColor = patternName.startsWith( "brush://" ) ? color : QColor();
+  QColor borderColor = !patternName.startsWith( "brush://" ) ? color : QColor();
+
+  /* Use WellKnownName tag to handle QT brush styles. */
+  wellKnownMarkerToSld( doc, graphicFillElem, patternName, fillColor, borderColor );
+}
+
+bool QgsSymbolLayerV2Utils::fillFromSld( QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color )
+{
+  QgsDebugMsg( "Entered." );
+
+  brushStyle = Qt::SolidPattern;
+  color = QColor( "#808080" );
+
+  if ( element.isNull() )
+  {
+    brushStyle = Qt::NoBrush;
+    color = QColor();
+    return true;
+  }
+
+  QDomElement graphicFillElem = element.firstChildElement( "GraphicFill" );
+  // if no GraphicFill element is found, it's a solid fill
+  if ( graphicFillElem.isNull() )
+  {
+    QgsStringMap svgParams = getSvgParameterList( element );
+    for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
+    {
+      QgsDebugMsg( QString( "found SvgParameter %1: %2" ).arg( it.key() ).arg( it.value() ) );
+
+      if ( it.key() == "fill" )
+        color = QColor( it.value() );
+      else if ( it.key() == "fill-opacity" )
+        color.setAlpha( decodeSldAlpha( it.value() ) );
+    }
+  }
+  else  // wellKnown marker
+  {
+    QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
+    if ( graphicElem.isNull() )
+      return false; // Graphic is required within GraphicFill
+
+    QString patternName = "square";
+    QColor fillColor, borderColor;
+    double borderWidth, size;
+    if ( !wellKnownMarkerFromSld( graphicFillElem, patternName, fillColor, borderColor, borderWidth, size ) )
+      return false;
+
+    brushStyle = decodeSldBrushStyle( patternName );
+    if ( brushStyle == Qt::NoBrush )
+      return false; // unable to decode brush style
+
+    QColor c = patternName.startsWith( "brush://" ) ? fillColor : borderColor;
+    if ( c.isValid() )
+      color = c;
+  }
+
+  return true;
+}
+
+void QgsSymbolLayerV2Utils::lineToSld( QDomDocument &doc, QDomElement &element,
+                                       Qt::PenStyle penStyle, QColor color, double width,
+                                       const Qt::PenJoinStyle *penJoinStyle, const Qt::PenCapStyle *penCapStyle,
+                                       const QVector<qreal> *customDashPattern, double dashOffset )
+{
+  QVector<qreal> dashPattern;
+  if ( penStyle == Qt::CustomDashLine && !customDashPattern )
+  {
+    element.appendChild( doc.createComment( "WARNING: Custom dash pattern required but not provided. Using default dash pattern." ) );
+    penStyle = Qt::DashLine;
+    customDashPattern = &dashPattern;
+  }
+
+  switch ( penStyle )
+  {
+    case Qt::NoPen:
+      return;
+
+    case Qt::SolidLine:
+      break;
+
+    case Qt::DashLine:
+      dashPattern.push_back( 4.0 );
+      dashPattern.push_back( 2.0 );
+      break;
+    case Qt::DotLine:
+      dashPattern.push_back( 1.0 );
+      dashPattern.push_back( 2.0 );
+      break;
+    case Qt::DashDotLine:
+      dashPattern.push_back( 4.0 );
+      dashPattern.push_back( 2.0 );
+      dashPattern.push_back( 1.0 );
+      dashPattern.push_back( 2.0 );
+      break;
+    case Qt::DashDotDotLine:
+      dashPattern.push_back( 4.0 );
+      dashPattern.push_back( 2.0 );
+      dashPattern.push_back( 1.0 );
+      dashPattern.push_back( 2.0 );
+      dashPattern.push_back( 1.0 );
+      dashPattern.push_back( 2.0 );
+      break;
+
+      case Qt::CustomDashLine:
+        Q_ASSERT( customDashPattern );
+        break;
+
+    default:
+      element.appendChild( doc.createComment( QString( "Qt::BrushStyle '%1'' not supported yet" ).arg( penStyle ) ) );
+      return;
+  }
+
+  if ( color.isValid() )
+  {
+    element.appendChild( createSvgParameterElement( doc, "stroke", color.name() ) );
+    if ( color.alpha() < 255 )
+      element.appendChild( createSvgParameterElement( doc, "stroke-opacity", encodeSldAlpha( color.alpha() ) ) );
+  }
+  if ( width > 0 )
+    element.appendChild( createSvgParameterElement( doc, "stroke-width", QString::number( width ) ) );
+  if ( penJoinStyle )
+    element.appendChild( createSvgParameterElement( doc, "stroke-linejoin", encodeSldLineJoinStyle( *penJoinStyle ) ) );
+  if ( penCapStyle )
+    element.appendChild( createSvgParameterElement( doc, "stroke-linecap", encodeSldLineCapStyle( *penCapStyle ) ) );
+
+  if ( customDashPattern && customDashPattern->size() > 0 )
+  {
+    element.appendChild( createSvgParameterElement( doc, "stroke-dasharray", encodeSldRealVector( *customDashPattern ) ) );
+    if ( !doubleNear( dashOffset, 0.0 ) )
+      element.appendChild( createSvgParameterElement( doc, "stroke-dashoffset", QString::number( dashOffset ) ) );
+  }
+}
+
+
+bool QgsSymbolLayerV2Utils::lineFromSld( QDomElement &element,
+                                         Qt::PenStyle &penStyle, QColor &color, double &width,
+                                         Qt::PenJoinStyle *penJoinStyle, Qt::PenCapStyle *penCapStyle,
+                                         QVector<qreal> *customDashPattern, double *dashOffset )
+{
+  QgsDebugMsg( "Entered." );
+
+  penStyle = Qt::SolidLine;
+  color = QColor( "#000000" );
+  width = 1;
+  if ( penJoinStyle )
+    *penJoinStyle = Qt::BevelJoin;
+  if ( penCapStyle )
+    *penCapStyle = Qt::SquareCap;
+  if ( customDashPattern )
+    customDashPattern->clear();
+  if ( dashOffset )
+    *dashOffset = 0;
+
+  if ( element.isNull() )
+  {
+    penStyle = Qt::NoPen;
+    color = QColor();
+    return true;
+  }
+
+  QgsStringMap svgParams = getSvgParameterList( element );
+  for ( QgsStringMap::iterator it = svgParams.begin(); it != svgParams.end(); ++it )
+  {
+    QgsDebugMsg( QString( "found SvgParameter %1: %2" ).arg( it.key() ).arg( it.value() ) );
+
+    if ( it.key() == "stroke" )
+    {
+      color = QColor( it.value() );
+    }
+    else if ( it.key() == "stroke-opacity" )
+    {
+      color.setAlpha( decodeSldAlpha( it.value() ) );
+    }
+    else if ( it.key() == "stroke-width" )
+    {
+      bool ok;
+      double w = it.value().toDouble( &ok );
+      if ( ok )
+        width = w;
+    }
+    else if ( it.key() == "stroke-linejoin" && penJoinStyle )
+    {
+      *penJoinStyle = decodeSldLineJoinStyle( it.value() );
+    }
+    else if ( it.key() == "stroke-linecap" && penCapStyle )
+    {
+      *penCapStyle = decodeSldLineCapStyle( it.value() );
+    }
+    else if ( it.key() == "stroke-dasharray" && customDashPattern )
+    {
+      *customDashPattern = decodeSldRealVector( it.value() );
+      if ( customDashPattern->size() > 0 )
+      {
+        // convert the dasharray to one of the QT pen style,
+        // if no match is found then set pen style to CustomDashLine
+        bool dashPatternFound = false;
+
+        if ( customDashPattern->count() == 2 )
+        {
+          if ( customDashPattern->at( 0 ) == 4.0 &&
+               customDashPattern->at( 1 ) == 2.0 )
+          {
+            penStyle = Qt::DashLine;
+            dashPatternFound = true;
+          }
+          else if ( customDashPattern->at( 0 ) == 1.0 &&
+                    customDashPattern->at( 1 ) == 2.0 )
+          {
+            penStyle = Qt::DotLine;
+            dashPatternFound = true;
+          }
+        }
+        else if ( customDashPattern->count() == 4 )
+        {
+          if ( customDashPattern->at( 0 ) == 4.0 &&
+               customDashPattern->at( 1 ) == 2.0 &&
+               customDashPattern->at( 2 ) == 1.0 &&
+               customDashPattern->at( 3 ) == 2.0 )
+          {
+            penStyle = Qt::DashDotLine;
+            dashPatternFound = true;
+          }
+        }
+        else if ( customDashPattern->count() == 6 )
+        {
+          if ( customDashPattern->at( 0 ) == 4.0 &&
+               customDashPattern->at( 1 ) == 2.0 &&
+               customDashPattern->at( 2 ) == 1.0 &&
+               customDashPattern->at( 3 ) == 2.0 &&
+               customDashPattern->at( 4 ) == 1.0 &&
+               customDashPattern->at( 5 ) == 2.0 )
+          {
+            penStyle = Qt::DashDotDotLine;
+            dashPatternFound = true;
+          }
+        }
+
+        // default case: set pen style to CustomDashLine
+        if ( !dashPatternFound )
+        {
+          penStyle = Qt::CustomDashLine;
+        }
+      }
+    }
+    else if ( it.key() == "stroke-dashoffset" && dashOffset )
+    {
+      bool ok;
+      double d = it.value().toDouble( &ok );
+      if ( ok )
+        *dashOffset = d;
+    }
+  }
+
+  return true;
+}
+
+void QgsSymbolLayerV2Utils::externalGraphicToSld( QDomDocument &doc, QDomElement &element,
+                                                  QString path, QString mime,
+                                                  QColor color, double size )
+{
+  QDomElement externalGraphicElem = doc.createElement( "se:ExternalGraphic" );
+  element.appendChild( externalGraphicElem );
+
+  createOnlineResourceElement( doc, externalGraphicElem, path, mime );
+
+  //TODO: missing a way to handle svg color. Should use <se:ColorReplacement>
+  Q_UNUSED( color );
+
+  if ( size >= 0 )
+  {
+    QDomElement sizeElem = doc.createElement( "se:Size" );
+    sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
+    element.appendChild( sizeElem );
+  }
+}
+
+bool QgsSymbolLayerV2Utils::externalGraphicFromSld( QDomElement &element,
+                                                    QString &path, QString &mime,
+                                                    QColor &color, double &size )
+{
+  QgsDebugMsg( "Entered." );
+  Q_UNUSED( color );
+
+  QDomElement externalGraphicElem = element.firstChildElement( "ExternalGraphic" );
+  if ( externalGraphicElem.isNull() )
+    return false;
+
+  onlineResourceFromSldElement( externalGraphicElem, path, mime );
+
+  QDomElement sizeElem = element.firstChildElement( "Size" );
+  if ( !sizeElem.isNull() )
+  {
+    bool ok;
+    double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
+    if ( ok )
+      size = s;
+  }
+
+  return true;
+}
+
+void QgsSymbolLayerV2Utils::externalMarkerToSld( QDomDocument &doc, QDomElement &element,
+                                                 QString path, QString format, int *markIndex,
+                                                 QColor color, double size )
+{
+  QDomElement markElem = doc.createElement( "se:Mark" );
+  element.appendChild( markElem );
+
+  createOnlineResourceElement( doc, markElem, path, format );
+
+  if ( markIndex )
+  {
+    QDomElement markIndexElem = doc.createElement( "se:MarkIndex" );
+    markIndexElem.appendChild( doc.createTextNode( QString::number( *markIndex ) ) );
+    markElem.appendChild( markIndexElem );
+  }
+
+  // <Fill>
+  QDomElement fillElem = doc.createElement( "se:Fill" );
+  fillToSld( doc, fillElem, Qt::SolidPattern, color );
+  markElem.appendChild( fillElem );
+
+  // <Size>
+  if ( !doubleNear( size, 0.0 ) && size > 0 )
+  {
+    QDomElement sizeElem = doc.createElement( "se:Size" );
+    sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
+    element.appendChild( sizeElem );
+  }
+}
+
+bool QgsSymbolLayerV2Utils::externalMarkerFromSld( QDomElement &element,
+                                                   QString &path, QString &format, int &markIndex,
+                                                   QColor &color, double &size )
+{
+  QgsDebugMsg( "Entered." );
+
+  color = QColor();
+  markIndex = -1;
+  size = -1;
+
+  QDomElement markElem = element.firstChildElement( "Mark" );
+  if ( markElem.isNull() )
+    return false;
+
+  onlineResourceFromSldElement( markElem, path, format );
+
+  QDomElement markIndexElem = markElem.firstChildElement( "MarkIndex" );
+  if ( !markIndexElem.isNull() )
+  {
+    bool ok;
+    int i = markIndexElem.firstChild().nodeValue().toInt( &ok );
+    if ( ok )
+      markIndex = i;
+  }
+
+  // <Fill>
+  QDomElement fillElem = markElem.firstChildElement( "Fill" );
+  Qt::BrushStyle b = Qt::SolidPattern;
+  fillFromSld( fillElem, b, color );
+  // ignore brush style, solid expected
+
+  // <Size>
+  QDomElement sizeElem = element.firstChildElement( "Size" );
+  if ( !sizeElem.isNull() )
+  {
+    bool ok;
+    double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
+    if ( ok )
+      size = s;
+  }
+
+  return true;
+}
+
+void QgsSymbolLayerV2Utils::wellKnownMarkerToSld( QDomDocument &doc, QDomElement &element,
+                                                  QString name, QColor color, QColor borderColor,
+                                                  double borderWidth, double size )
+{
+  QDomElement markElem = doc.createElement( "se:Mark" );
+  element.appendChild( markElem );
+
+  QDomElement wellKnownNameElem = doc.createElement( "se:WellKnownName" );
+  wellKnownNameElem.appendChild( doc.createTextNode(  name ) );
+  markElem.appendChild( wellKnownNameElem );
+
+  // <Fill>
+  if ( color.isValid() )
+  {
+    QDomElement fillElem = doc.createElement( "se:Fill" );
+    fillToSld( doc, fillElem, Qt::SolidPattern, color );
+    markElem.appendChild( fillElem );
+  }
+
+  // <Stroke>
+  if ( borderColor.isValid() )
+  {
+    QDomElement strokeElem = doc.createElement( "se:Stroke" );
+    lineToSld( doc, strokeElem, Qt::SolidLine, borderColor, borderWidth );
+    markElem.appendChild( strokeElem );
+  }
+
+  // <Size>
+  if ( !doubleNear( size, 0.0 ) && size > 0 )
+  {
+    QDomElement sizeElem = doc.createElement( "se:Size" );
+    sizeElem.appendChild( doc.createTextNode( QString::number( size ) ) );
+    element.appendChild( sizeElem );
+  }
+}
+
+bool QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( QDomElement &element,
+                                                    QString &name, QColor &color, QColor &borderColor,
+                                                    double &borderWidth, double &size )
+{
+  QgsDebugMsg( "Entered." );
+
+  name = "square";
+  color = QColor();
+  borderColor = QColor( "#000000" );
+  borderWidth = 1;
+  size = 6;
+
+  QDomElement markElem = element.firstChildElement( "Mark" );
+  if ( markElem.isNull() )
+    return false;
+
+  QDomElement wellKnownNameElem = markElem.firstChildElement( "WellKnownName" );
+  if ( !wellKnownNameElem.isNull() )
+  {
+    name = wellKnownNameElem.firstChild().nodeValue();
+    QgsDebugMsg( "found Mark with well known name: " + name );
+  }
+
+  // <Fill>
+  QDomElement fillElem = markElem.firstChildElement( "Fill" );
+  Qt::BrushStyle b = Qt::SolidPattern;
+  fillFromSld( fillElem, b, color );
+  // ignore brush style, solid expected
+
+  // <Stroke>
+  QDomElement strokeElem = markElem.firstChildElement( "Stroke" );
+  Qt::PenStyle p = Qt::SolidLine;
+  lineFromSld( strokeElem, p, borderColor, borderWidth );
+  // ignore border style, solid expected
+
+  // <Size>
+  QDomElement sizeElem = element.firstChildElement( "Size" );
+  if ( !sizeElem.isNull() )
+  {
+    bool ok;
+    double s = sizeElem.firstChild().nodeValue().toDouble( &ok );
+    if ( ok )
+      size = s;
+  }
+
+  return true;
+}
+
+void QgsSymbolLayerV2Utils::createRotationElement( QDomDocument &doc, QDomElement &element, QString rotationFunc )
+{
+  if ( !rotationFunc.isEmpty() )
+  {
+    QDomElement rotationElem = doc.createElement( "se:Rotation" );
+    createFunctionElement( doc, rotationElem, rotationFunc );
+    element.appendChild( rotationElem );
+  }
+}
+
+bool QgsSymbolLayerV2Utils::rotationFromSldElement( QDomElement &element, QString &rotationFunc )
+{
+  QDomElement rotationElem = element.firstChildElement( "Rotation" );
+  if ( !rotationElem.isNull() )
+  {
+    functionFromSldElement( rotationElem, rotationFunc );
+  }
+  return true;
+}
+
+
+void QgsSymbolLayerV2Utils::createOpacityElement( QDomDocument &doc, QDomElement &element, QString alphaFunc )
+{
+  if ( !alphaFunc.isEmpty() )
+  {
+    QDomElement opacityElem = doc.createElement( "se:Opacity" );
+    createFunctionElement( doc, opacityElem, alphaFunc );
+    element.appendChild( opacityElem );
+  }
+}
+
+bool QgsSymbolLayerV2Utils::opacityFromSldElement( QDomElement &element, QString &alphaFunc )
+{
+  QDomElement opacityElem = element.firstChildElement( "Opacity" );
+  if ( !opacityElem.isNull() )
+  {
+    functionFromSldElement( opacityElem, alphaFunc );
+  }
+  return true;
+}
+
+void QgsSymbolLayerV2Utils::createDisplacementElement( QDomDocument &doc, QDomElement &element, QPointF offset )
+{
+  if ( offset.isNull() )
+    return;
+
+  QDomElement displacementElem = doc.createElement( "se:Displacement" );
+  element.appendChild( displacementElem );
+
+  QDomElement dispXElem = doc.createElement( "se:DisplacementX" );
+  dispXElem.appendChild( doc.createTextNode( QString::number( offset.x() ) ) );
+
+  QDomElement dispYElem = doc.createElement( "se:DisplacementY" );
+  dispYElem.appendChild( doc.createTextNode( QString::number( offset.y() ) ) );
+
+  displacementElem.appendChild( dispXElem );
+  displacementElem.appendChild( dispYElem );
+}
+
+bool QgsSymbolLayerV2Utils::displacementFromSldElement( QDomElement &element, QPointF &offset )
+{
+  offset = QPointF( 0, 0 );
+
+  QDomElement displacementElem = element.firstChildElement( "Displacement" );
+  if ( displacementElem.isNull() )
+    return true;
+
+  QDomElement dispXElem = element.firstChildElement( "DisplacementX" );
+  if ( !dispXElem.isNull() )
+  {
+    bool ok;
+    double offsetX = dispXElem.firstChild().nodeValue().toDouble( &ok );
+    if ( ok )
+      offset.setX( offsetX );
+  }
+
+  QDomElement dispYElem = element.firstChildElement( "DisplacementY" );
+  if ( !dispYElem.isNull() )
+  {
+    bool ok;
+    double offsetY = dispYElem.firstChild().nodeValue().toDouble( &ok );
+    if ( ok )
+      offset.setY( offsetY );
+  }
+
+  return true;
+}
+
+void QgsSymbolLayerV2Utils::labelTextToSld( QDomDocument &doc, QDomElement &element,
+                                            QString label, QFont font,
+                                            QColor color, double size )
+{
+  QDomElement labelElem = doc.createElement( "se:Label" );
+  labelElem.appendChild( doc.createTextNode( label ) );
+  element.appendChild( labelElem );
+
+  QDomElement fontElem = doc.createElement( "se:Font" );
+  element.appendChild( fontElem );
+
+  fontElem.appendChild( createSvgParameterElement( doc, "font-family", font.family() ) );
+#if 0
+  fontElem.appendChild( createSldParameterElement( doc, "font-style", encodeSldFontStyle( font.style() ) ) );
+  fontElem.appendChild( createSldParameterElement( doc, "font-weight", encodeSldFontWeight( font.weight() ) ) );
+#endif
+  fontElem.appendChild( createSvgParameterElement( doc, "font-size", QString::number( size ) ) );
+
+  // <Fill>
+  if ( color.isValid() )
+  {
+    QDomElement fillElem = doc.createElement( "Fill" );
+    fillToSld( doc, fillElem, Qt::SolidPattern, color );
+    element.appendChild( fillElem );
+  }
+}
+
+void QgsSymbolLayerV2Utils::createGeometryElement( QDomDocument &doc, QDomElement &element, QString geomFunc )
+{
+  if ( geomFunc.isEmpty() )
+    return;
+
+  QDomElement geometryElem = doc.createElement( "Geometry" );
+  element.appendChild( geometryElem );
+
+  /* About using a function withing the Geometry tag.
+   *
+   * The SLD specification <= 1.1 is vague:
+   * "In principle, a fixed geometry could be defined using GML or
+   * operators could be defined for computing the geometry from
+   * references or literals. However, using a feature property directly
+   * is by far the most commonly useful method."
+   *
+   * Even if it seems that specs should take care all the possible cases,
+   * looking at the XML schema fragment that encodes the Geometry element,
+   * it has to be a PropertyName element:
+   *   <xsd:element name="Geometry">
+   *       <xsd:complexType>
+   *           <xsd:sequence>
+   *               <xsd:element ref="ogc:PropertyName"/>
+   *           </xsd:sequence>
+   *       </xsd:complexType>
+   *   </xsd:element>
+   *
+   * Anyway we will use a ogc:Function to handle geometry transformations
+   * like offset, centroid, ...
+   */
+
+  createFunctionElement( doc, geometryElem, geomFunc );
+}
+
+bool QgsSymbolLayerV2Utils::geometryFromSldElement( QDomElement &element, QString &geomFunc )
+{
+  QDomElement geometryElem = element.firstChildElement( "Geometry" );
+  if ( geometryElem.isNull() )
+    return true;
+
+  return functionFromSldElement( geometryElem, geomFunc );
+}
+
+bool QgsSymbolLayerV2Utils::createFunctionElement( QDomDocument &doc, QDomElement &element, QString function )
+{
+  // let's use QgsExpression to generate the SLD for the function
+  QgsExpression expr( function );
+  if ( expr.hasParserError() )
+  {
+    element.appendChild( doc.createComment( "Parser Error: " + expr.parserErrorString() + " - Expression was: " + function  ) );
+    return false;
+  }
+  expr.toOgcFilter( doc, element );
+  return true;
+}
+
+bool QgsSymbolLayerV2Utils::functionFromSldElement( QDomElement &element, QString &function )
+{
+  QgsDebugMsg( "Entered." );
+
+  QgsExpression *expr = QgsExpression::createFromOgcFilter( element );
+  if ( !expr )
+    return false;
+
+  bool valid = expr->hasParserError();
+  if ( !valid )
+  {
+    QgsDebugMsg( "parser error: " + expr->parserErrorString() );
+  }
+  else
+  {
+    function = expr->dump();
+  }
+
+  delete expr;
+  return valid;
+}
+
+void QgsSymbolLayerV2Utils::createOnlineResourceElement( QDomDocument &doc, QDomElement &element,
+                                                         QString path, QString format )
+{
+  QDomElement onlineResourceElem = doc.createElement( "OnlineResource" );
+  onlineResourceElem.setAttribute( "xlink:type", "simple" );
+  onlineResourceElem.setAttribute( "xlink:href", path );
+  element.appendChild( onlineResourceElem );
+
+  QDomElement formatElem = doc.createElement( "Format" );
+  formatElem.appendChild( doc.createTextNode( format ) );
+  element.appendChild( formatElem );
+}
+
+bool QgsSymbolLayerV2Utils::onlineResourceFromSldElement( QDomElement &element, QString &path, QString &format )
+{
+  QgsDebugMsg( "Entered." );
+
+  QDomElement onlineResourceElem = element.firstChildElement( "OnlineResource" );
+  if ( onlineResourceElem.isNull() )
+    return false;
+
+  path = onlineResourceElem.attributeNS( "http://www.w3.org/1999/xlink", "href" );
+
+  QDomElement formatElem = element.firstChildElement( "Format" );
+  if ( formatElem.isNull() )
+    return false; // OnlineResource requires a Format sibling element
+
+  format = formatElem.firstChild().nodeValue();
+  return true;
+}
+
+
+QDomElement QgsSymbolLayerV2Utils::createSvgParameterElement( QDomDocument &doc, QString name, QString value )
+{
+  QDomElement nodeElem = doc.createElement( "se:SvgParameter" );
+  nodeElem.setAttribute( "name", name );
+  nodeElem.appendChild( doc.createTextNode( value ) );
+  return nodeElem;
+}
+
+QgsStringMap QgsSymbolLayerV2Utils::getSvgParameterList( QDomElement &element )
+{
+  QgsStringMap params;
+
+  QDomElement paramElem = element.firstChildElement();
+  while( !paramElem.isNull() )
+  {
+    if ( paramElem.localName() == "SvgParameter" || paramElem.localName() == "CssParameter" )
+    {
+      QString name = paramElem.attribute( "name" );
+      QString value = paramElem.firstChild().nodeValue();
+
+      if ( !name.isEmpty() && !value.isEmpty() )
+        params[ name ] = value;
+    }
+
+    paramElem = paramElem.nextSiblingElement();
+  }
+
+  return params;
+}
+
+QDomElement QgsSymbolLayerV2Utils::createVendorOptionElement( QDomDocument &doc, QString name, QString value )
+{
+  QDomElement nodeElem = doc.createElement( "VendorOption" );
+  nodeElem.setAttribute( "name", name );
+  nodeElem.appendChild( doc.createTextNode( value ) );
+  return nodeElem;
+}
+
+QgsStringMap QgsSymbolLayerV2Utils::getVendorOptionList( QDomElement &element )
+{
+  QgsStringMap params;
+
+  QDomElement paramElem = element.firstChildElement( "VendorOption" );
+  while( !paramElem.isNull() )
+  {
+    QString name = paramElem.attribute( "name" );
+    QString value = paramElem.firstChild().nodeValue();
+
+    if ( !name.isEmpty() && !value.isEmpty() )
+      params[ name ] = value;
+
+    paramElem = paramElem.nextSiblingElement( "VendorOption" );
+  }
+
+  return params;
+}
+
+
 QgsStringMap QgsSymbolLayerV2Utils::parseProperties( QDomElement& element )
 {
   QgsStringMap props;
@@ -643,7 +2267,7 @@ QDomElement QgsSymbolLayerV2Utils::saveSymbols( QgsSymbolV2Map& symbols, QString
 void QgsSymbolLayerV2Utils::clearSymbolMap( QgsSymbolV2Map& symbols )
 {
   foreach( QString name, symbols.keys() )
-  delete symbols.value( name );
+    delete symbols.value( name );
   symbols.clear();
 }
 
diff --git a/src/core/symbology-ng/qgssymbollayerv2utils.h b/src/core/symbology-ng/qgssymbollayerv2utils.h
index 4631e90..3f75cd0 100644
--- a/src/core/symbology-ng/qgssymbollayerv2utils.h
+++ b/src/core/symbology-ng/qgssymbollayerv2utils.h
@@ -6,16 +6,17 @@
 #include <QMap>
 #include <Qt>
 #include <QtCore>
+#include <QFont>
+#include <QColor>
 #include "qgssymbolv2.h"
+#include "qgis.h"
 
-class QgsSymbolV2;
 class QgsSymbolLayerV2;
 class QgsVectorColorRampV2;
 
 typedef QMap<QString, QString> QgsStringMap;
 typedef QMap<QString, QgsSymbolV2* > QgsSymbolV2Map;
 
-class QColor;
 class QDomDocument;
 class QDomElement;
 class QIcon;
@@ -30,6 +31,15 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
     static QString encodeColor( QColor color );
     static QColor decodeColor( QString str );
 
+    static QString encodeSldAlpha( int alpha );
+    static int decodeSldAlpha( QString str );
+
+    static QString encodeSldFontStyle( QFont::Style style );
+    static QFont::Style decodeSldFontStyle( QString str );
+
+    static QString encodeSldFontWeight( int weight );
+    static int decodeSldFontWeight( QString str );
+
     static QString encodePenStyle( Qt::PenStyle style );
     static Qt::PenStyle decodePenStyle( QString str );
 
@@ -39,18 +49,33 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
     static QString encodePenCapStyle( Qt::PenCapStyle style );
     static Qt::PenCapStyle decodePenCapStyle( QString str );
 
+    static QString encodeSldLineJoinStyle( Qt::PenJoinStyle style );
+    static Qt::PenJoinStyle decodeSldLineJoinStyle( QString str );
+
+    static QString encodeSldLineCapStyle( Qt::PenCapStyle style );
+    static Qt::PenCapStyle decodeSldLineCapStyle( QString str );
+
     static QString encodeBrushStyle( Qt::BrushStyle style );
     static Qt::BrushStyle decodeBrushStyle( QString str );
 
+    static QString encodeSldBrushStyle( Qt::BrushStyle style );
+    static Qt::BrushStyle decodeSldBrushStyle( QString str );
+
     static QString encodePoint( QPointF point );
     static QPointF decodePoint( QString str );
 
     static QString encodeRealVector( const QVector<qreal>& v );
     static QVector<qreal> decodeRealVector( const QString& s );
 
+    static QString encodeSldRealVector( const QVector<qreal>& v );
+    static QVector<qreal> decodeSldRealVector( const QString& s );
+
     static QString encodeOutputUnit( QgsSymbolV2::OutputUnit unit );
     static QgsSymbolV2::OutputUnit decodeOutputUnit( QString str );
 
+    static QString encodeSldUom( QgsSymbolV2::OutputUnit unit, double *scaleFactor );
+    static QgsSymbolV2::OutputUnit decodeSldUom( QString str, double *scaleFactor );
+
     static QIcon symbolPreviewIcon( QgsSymbolV2* symbol, QSize size );
     static QIcon symbolLayerPreviewIcon( QgsSymbolLayerV2* layer, QgsSymbolV2::OutputUnit u, QSize size );
     static QIcon colorRampPreviewIcon( QgsVectorColorRampV2* ramp, QSize size );
@@ -62,6 +87,87 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
     static QgsSymbolLayerV2* loadSymbolLayer( QDomElement& element );
     static QDomElement saveSymbol( QString name, QgsSymbolV2* symbol, QDomDocument& doc, QgsSymbolV2Map* subSymbols = NULL );
 
+    static bool createSymbolLayerV2ListFromSld( QDomElement& element, QGis::GeometryType geomType, QgsSymbolLayerV2List &layers );
+
+    static QgsSymbolLayerV2* createFillLayerFromSld( QDomElement &element );
+    static QgsSymbolLayerV2* createLineLayerFromSld( QDomElement &element );
+    static QgsSymbolLayerV2* createMarkerLayerFromSld( QDomElement &element );
+
+    static bool convertPolygonSymbolizerToPointMarker( QDomElement &element, QgsSymbolLayerV2List &layerList );
+    static bool hasExternalGraphic( QDomElement &element );
+    static bool hasWellKnownMark( QDomElement &element );
+
+    static bool needFontMarker( QDomElement &element );
+    static bool needSvgMarker( QDomElement &element );
+    static bool needEllipseMarker( QDomElement &element );
+    static bool needMarkerLine( QDomElement &element );
+    static bool needLinePatternFill( QDomElement &element );
+    static bool needPointPatternFill( QDomElement &element );
+    static bool needSvgFill( QDomElement &element );
+
+    static void fillToSld( QDomDocument &doc, QDomElement &element,
+                           Qt::BrushStyle brushStyle, QColor color = QColor() );
+    static bool fillFromSld( QDomElement &element,
+                             Qt::BrushStyle &brushStyle, QColor &color );
+
+    static void lineToSld( QDomDocument &doc, QDomElement &element,
+                           Qt::PenStyle penStyle, QColor color, double width = -1,
+                           const Qt::PenJoinStyle *penJoinStyle = 0, const Qt::PenCapStyle *penCapStyle = 0,
+                           const QVector<qreal> *customDashPattern = 0, double dashOffset = 0.0 );
+    static bool lineFromSld( QDomElement &element,
+                             Qt::PenStyle &penStyle, QColor &color, double &width,
+                             Qt::PenJoinStyle *penJoinStyle = 0, Qt::PenCapStyle *penCapStyle = 0,
+                             QVector<qreal> *customDashPattern = 0, double *dashOffset = 0 );
+
+    static void externalGraphicToSld( QDomDocument &doc, QDomElement &element,
+                                      QString path, QString mime,
+                                      QColor color, double size = -1 );
+    static bool externalGraphicFromSld( QDomElement &element,
+                                        QString &path, QString &mime,
+                                        QColor &color, double &size );
+
+    static void wellKnownMarkerToSld( QDomDocument &doc, QDomElement &element,
+                                      QString name, QColor color, QColor borderColor = QColor(),
+                                      double borderWidth = -1, double size = -1 );
+    static bool wellKnownMarkerFromSld( QDomElement &element,
+                                        QString &name, QColor &color, QColor &borderColor,
+                                        double &borderWidth, double &size );
+
+    static void externalMarkerToSld( QDomDocument &doc, QDomElement &element,
+                                     QString path, QString format, int *markIndex = 0,
+                                     QColor color = QColor(), double size = -1 );
+    static bool externalMarkerFromSld( QDomElement &element,
+                                       QString &path, QString &format, int &markIndex,
+                                       QColor &color, double &size );
+
+
+    static void labelTextToSld( QDomDocument &doc, QDomElement &element, QString label,
+                                QFont font, QColor color = QColor(), double size = -1 );
+
+    static void createRotationElement( QDomDocument &doc, QDomElement &element, QString rotationFunc );
+    static bool rotationFromSldElement( QDomElement &element, QString &rotationFunc );
+
+    static void createOpacityElement( QDomDocument &doc, QDomElement &element, QString alphaFunc );
+    static bool opacityFromSldElement( QDomElement &element, QString &alphaFunc );
+
+    static void createDisplacementElement( QDomDocument &doc, QDomElement &element, QPointF offset );
+    static bool displacementFromSldElement( QDomElement &element, QPointF &offset );
+
+    static void createOnlineResourceElement( QDomDocument &doc, QDomElement &element, QString path, QString format );
+    static bool onlineResourceFromSldElement( QDomElement &element, QString &path, QString &format );
+
+    static void createGeometryElement( QDomDocument &doc, QDomElement &element, QString geomFunc );
+    static bool geometryFromSldElement( QDomElement &element, QString &geomFunc );
+
+    static bool createFunctionElement( QDomDocument &doc, QDomElement &element, QString function );
+    static bool functionFromSldElement( QDomElement &element, QString &function );
+
+    static QDomElement createSvgParameterElement( QDomDocument &doc, QString name, QString value );
+    static QgsStringMap getSvgParameterList( QDomElement &element );
+
+    static QDomElement createVendorOptionElement( QDomDocument &doc, QString name, QString value );
+    static QgsStringMap getVendorOptionList( QDomElement &element );
+
     static QgsStringMap parseProperties( QDomElement& element );
     static void saveProperties( QgsStringMap props, QDomDocument& doc, QDomElement& element );
 
diff --git a/src/core/symbology-ng/qgssymbolv2.cpp b/src/core/symbology-ng/qgssymbolv2.cpp
index b66f528..b8a83a4 100644
--- a/src/core/symbology-ng/qgssymbolv2.cpp
+++ b/src/core/symbology-ng/qgssymbolv2.cpp
@@ -253,6 +253,19 @@ QString QgsSymbolV2::dump()
   return s;
 }
 
+void QgsSymbolV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
+{
+  props[ "alpha" ] = QString::number( alpha() );
+  double scaleFactor = 1.0;
+  props[ "uom" ] = QgsSymbolLayerV2Utils::encodeSldUom( outputUnit(), &scaleFactor );
+  props[ "uomScale" ] = scaleFactor != 1 ? QString::number( scaleFactor ) : "";
+
+  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
+  {
+    ( *it )->toSld( doc, element, props );
+  }
+}
+
 QgsSymbolLayerV2List QgsSymbolV2::cloneLayers() const
 {
   QgsSymbolLayerV2List lst;
diff --git a/src/core/symbology-ng/qgssymbolv2.h b/src/core/symbology-ng/qgssymbolv2.h
index e9e6af1..0b96f4e 100644
--- a/src/core/symbology-ng/qgssymbolv2.h
+++ b/src/core/symbology-ng/qgssymbolv2.h
@@ -12,6 +12,9 @@ class QPainter;
 class QSize;
 class QPointF;
 class QPolygonF;
+
+class QDomDocument;
+class QDomElement;
 //class
 
 class QgsFeature;
@@ -89,6 +92,8 @@ class CORE_EXPORT QgsSymbolV2
 
     virtual QgsSymbolV2* clone() const = 0;
 
+    void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;
+
     OutputUnit outputUnit() const { return mOutputUnit; }
     void setOutputUnit( OutputUnit u ) { mOutputUnit = u; }
 
diff --git a/src/core/symbology-ng/qgsvectorfieldsymbollayer.cpp b/src/core/symbology-ng/qgsvectorfieldsymbollayer.cpp
index 9959d21..b97fae0 100644
--- a/src/core/symbology-ng/qgsvectorfieldsymbollayer.cpp
+++ b/src/core/symbology-ng/qgsvectorfieldsymbollayer.cpp
@@ -177,6 +177,18 @@ QgsStringMap QgsVectorFieldSymbolLayer::properties() const
   return properties;
 }
 
+void QgsVectorFieldSymbolLayer::toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const
+{
+  element.appendChild( doc.createComment( "VectorField not implemented yet..." ) );
+  mLineSymbol->toSld( doc, element, props );
+}
+
+QgsSymbolLayerV2* QgsVectorFieldSymbolLayer::createFromSld( QDomElement &element )
+{
+  Q_UNUSED( element );
+  return NULL;
+}
+
 void QgsVectorFieldSymbolLayer::drawPreviewIcon( QgsSymbolV2RenderContext& context, QSize size )
 {
   if ( mLineSymbol )
diff --git a/src/core/symbology-ng/qgsvectorfieldsymbollayer.h b/src/core/symbology-ng/qgsvectorfieldsymbollayer.h
index 8f55b95..367253b 100644
--- a/src/core/symbology-ng/qgsvectorfieldsymbollayer.h
+++ b/src/core/symbology-ng/qgsvectorfieldsymbollayer.h
@@ -47,6 +47,7 @@ class CORE_EXPORT QgsVectorFieldSymbolLayer: public QgsMarkerSymbolLayerV2
     ~QgsVectorFieldSymbolLayer();
 
     static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
+    static QgsSymbolLayerV2* createFromSld( QDomElement &element );
 
     QString layerType() const { return "VectorField"; }
 
@@ -60,6 +61,8 @@ class CORE_EXPORT QgsVectorFieldSymbolLayer: public QgsMarkerSymbolLayerV2
     QgsSymbolLayerV2* clone() const;
     QgsStringMap properties() const;
 
+    void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;
+
     void drawPreviewIcon( QgsSymbolV2RenderContext& context, QSize size );
 
     QSet<QString> usedAttributes() const;

-- 
The Quantum GIS in Debian project



More information about the Pkg-grass-devel mailing list