You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@xalan.apache.org by Mark Biamonte <Ma...@merant.com> on 2001/01/29 19:16:06 UTC

XPath parser and names with leading underscore

The XPath Parser has problems with node names that begin with a leading
underscore.
 
Given the following XML 
<CTABLE>
    <_Record>
        <CHARCOL>bc</CHARCOL>
    </_Record>
    <_Record>
        <CHARCOL>cde</CHARCOL>
    </_Record>
</CTABLE>
 
I try to execute the following (where m_XmlDocument contains the above XML)
 
    XPathAPI    xpathParser = new XPathAPI();
    NodeList    m_Rows = xpathParser.selectNodeList(m_XmlDocument,
"/CTABLE/_Record");
        
selectNodeList throws an exception with the message
 
    Extra illegal tokens:'_Record'
 
I am able to work around the problem if use the following expression instead
 
    NodeList    m_Rows = xpathParser.selectNodeList(m_XmlDocument,
"/CTABLE/*[local-name()='_Record']");
 
Per the XML 1.0 Specification the underscore character is one of the few non
letter characters that an XML tag name can begin with.  The name production
from the XML Spec is
 
    Name    ::=    (Letter | '_' | ':') (NameChar)* 
 
I have traced the problem down to the Step function in XPathParser.java.  At
the bottom of the function is an else if statement that checks to see if the
first letter of the token is a letter as indicated below.  In the case of a
tag name that begins with an underscore, this test fails and the basics
function is not called and processing of the expression basically stops
there.
 
I am using the xalan-java version 2.0.D07 drop.  
 

XPathParser.java
=================================================
...
 
protected void Step() throws javax.xml.transform.TransformerException
  {
 
    int opPos = m_ops.m_opMap[OpMap.MAPINDEX_LENGTH];
 
    if (tokenIs("."))
    {
 ...
    }
    else if (tokenIs(".."))
    {
  ...
    }
 
    // There is probably a better way to test for this 
    // transition... but it gets real hairy if you try 
    // to do it in basis().
    else if (tokenIs('*') || tokenIs( '@' <mailto:'@'> ) || tokenIs('/')
<======== Problem here?        
             || Character.isLetter(m_token.charAt(0)))
    {
      Basis();
 
      while (tokenIs('['))
      {
        Predicate();
      }
 
      // Tell how long the entire step is.
      m_ops.m_opMap[opPos + OpMap.MAPINDEX_LENGTH] =
        m_ops.m_opMap[OpMap.MAPINDEX_LENGTH] - opPos;
    }
  }
 
...

-------------------------
Mark Biamonte
Morrisville Office
(919) 461-4354
Mark.Biamonte@merant.com