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