diff --git a/src/backend/utils/adt/xpath_parser.c b/src/backend/utils/adt/xpath_parser.c
index f22ec76..1d8d93c 100644
--- a/src/backend/utils/adt/xpath_parser.c
+++ b/src/backend/utils/adt/xpath_parser.c
@@ -41,6 +41,8 @@ typedef enum
 	XPATH_TOKEN_NAME,
 	XPATH_TOKEN_STRING,
 	XPATH_TOKEN_NUMBER,
+	XPATH_TOKEN_COLON,
+	XPATH_TOKEN_DCOLON,
 	XPATH_TOKEN_OTHER
 }	XPathTokenType;
 
@@ -68,6 +70,7 @@ typedef struct ParserData
 #define IS_NODENAME_CHAR(c)		(IS_NODENAME_FIRSTCHAR(c) || (c) == '-' || (c) == '.' || \
 								 ((c) >= '0' && (c) <= '9'))
 
+#define TOKEN_IS_EMPTY(t)	((t)->ttype == XPATH_TOKEN_NONE)
 
 /*
  * Returns next char after last char of token - XPath lexer
@@ -112,6 +115,17 @@ getXPathToken(char *str, XPathTokenInfo * ti)
 
 			ti->ttype = XPATH_TOKEN_STRING;
 		}
+		else if (c == ':')
+		{
+			/* look ahead to detect a doulbe-colon */
+			if (*str == ':')
+			{
+				ti->ttype = XPATH_TOKEN_DCOLON;
+				str++;
+			}
+			else
+				ti->ttype = XPATH_TOKEN_COLON;
+		}
 		else
 			ti->ttype = XPATH_TOKEN_OTHER;
 
@@ -165,6 +179,7 @@ pushXPathToken(XPathParserData * parser, XPathTokenInfo * ti)
 
 	memcpy(&parser->buffer, ti, sizeof(XPathTokenInfo));
 	parser->buffer_is_empty = false;
+	ti->ttype = XPATH_TOKEN_NONE;
 }
 
 /*
@@ -179,6 +194,9 @@ writeXPathToken(StringInfo str, XPathTokenInfo * ti)
 		appendBinaryStringInfo(str, ti->start, ti->length);
 	else
 		appendStringInfoChar(str, *ti->start);
+
+	/* this token is comsumed */
+	ti->ttype = XPATH_TOKEN_NONE;
 }
 
 /*
@@ -192,7 +210,7 @@ _transformXPath(StringInfo str, XPathParserData * parser,
 {
 	XPathTokenInfo t1,
 				t2;
-	bool		token_is_tagname = false;
+	bool		tagname_needs_defnsp = false;
 	bool		token_is_tagattrib = false;
 
 	nextXPathToken(parser, &t1);
@@ -203,7 +221,11 @@ _transformXPath(StringInfo str, XPathParserData * parser,
 		{
 			case XPATH_TOKEN_NUMBER:
 			case XPATH_TOKEN_STRING:
-				token_is_tagname = false;
+				/*
+				 * string cannot be a tag name. write out it immediately and
+				 * go ahead
+				 */
+				tagname_needs_defnsp = false;
 				token_is_tagattrib = false;
 
 				writeXPathToken(str, &t1);
@@ -212,8 +234,6 @@ _transformXPath(StringInfo str, XPathParserData * parser,
 
 			case XPATH_TOKEN_NAME:
 				{
-					bool		is_qual_name = false;
-
 					/* inside predicate ignore keywords "and" "or" */
 					if (inside_predicate)
 					{
@@ -226,53 +246,56 @@ _transformXPath(StringInfo str, XPathParserData * parser,
 						}
 					}
 
-					token_is_tagname = true;
+					/* look ahead what is following the name token */
+					tagname_needs_defnsp = true;
 					nextXPathToken(parser, &t2);
-					if (t2.ttype == XPATH_TOKEN_OTHER)
+					if (t2.ttype == XPATH_TOKEN_COLON)
+					{
+						/* t1 is a quilified node name. no need to add default one. */
+						tagname_needs_defnsp = false;
+						writeXPathToken(str, &t1);	/* namespace name */
+						writeXPathToken(str, &t2);	/* colon */
+						/* get node name */
+						nextXPathToken(parser, &t1);
+					}
+					else if (t2.ttype == XPATH_TOKEN_DCOLON)
+					{
+						/* t1 is an axis name. write out as it is */
+						if (strncmp(t1.start, "attribute", 9) == 0 && t1.length == 9)
+							token_is_tagattrib = true;
+
+						writeXPathToken(str, &t1);	/* axis name */
+						writeXPathToken(str, &t2);	/* double colon */
+
+						/*
+						 * The next token may be qualified tag name, process
+						 * it as a fresh token.
+						 */
+						nextXPathToken(parser, &t1);
+						break;
+					}
+					else if (t2.ttype == XPATH_TOKEN_OTHER)
 					{
+						/* function name doesn't require namespace */
 						if (*t2.start == '(')
-							token_is_tagname = false;
-						else if (*t2.start == ':')
-						{
-							XPathTokenInfo t3;
-
-							nextXPathToken(parser, &t3);
-							if (t3.ttype == XPATH_TOKEN_OTHER && *t3.start == ':'
-									 && strncmp(t1.start, "attribute", 9) == 0)
-							{
-								/* other syntax for attribute, where we should not apply def namespace */
-								appendStringInfo(str, "attribute::");
-								nextXPathToken(parser, &t1);
-								token_is_tagattrib = true;
-								break;
-							}
-							else
-							{
-								pushXPathToken(parser, &t3);
-								is_qual_name = true;
-							}
-						}
+							tagname_needs_defnsp = false;
+						else
+							pushXPathToken(parser, &t2);
 					}
 
-					if (token_is_tagname && !token_is_tagattrib
-								 && !is_qual_name && def_namespace_name != NULL)
+					if (tagname_needs_defnsp && !token_is_tagattrib &&
+						def_namespace_name != NULL)
 						appendStringInfo(str, "%s:", def_namespace_name);
 
 					token_is_tagattrib = false;
 
-					writeXPathToken(str, &t1);
+					/* write maybe-tagname if not consumed */
+					if (!TOKEN_IS_EMPTY(&t1))
+						writeXPathToken(str, &t1);
 
-					if (is_qual_name)
-					{
+					/* output t2 if not consumed yet */
+					if (!TOKEN_IS_EMPTY(&t2))
 						writeXPathToken(str, &t2);
-						nextXPathToken(parser, &t1);
-						if (t1.ttype == XPATH_TOKEN_NAME)
-							writeXPathToken(str, &t1);
-						else
-							pushXPathToken(parser, &t1);
-					}
-					else
-						pushXPathToken(parser, &t2);
 
 					nextXPathToken(parser, &t1);
 				}
@@ -283,7 +306,6 @@ _transformXPath(StringInfo str, XPathParserData * parser,
 					char		c = *t1.start;
 
 					token_is_tagattrib = false;
-					token_is_tagname = false;
 
 					writeXPathToken(str, &t1);
 
@@ -307,10 +329,14 @@ _transformXPath(StringInfo str, XPathParserData * parser,
 				}
 				break;
 
+			case XPATH_TOKEN_COLON:
+			case XPATH_TOKEN_DCOLON:
 			case XPATH_TOKEN_NONE:
 				elog(ERROR, "should not be here");
 		}
 	}
+
+	elog(LOG, "\"%s\"", str->data);
 }
 
 void
