public Matcher parse(String xpath) {
        if (xpath.equals("/text()")) {
            return TextMatcher.INSTANCE;
        } else if (xpath.equals("/node()")) {
            return NodeMatcher.INSTANCE;
        } else if (xpath.equals("/descendant::node()") ||
                xpath.equals("/descendant:node()")) { // for compatibility
            return new CompositeMatcher(TextMatcher.INSTANCE,
                    new ChildMatcher(new SubtreeMatcher(NodeMatcher.INSTANCE)));
        } else if (xpath.equals("/@*")) {
            return AttributeMatcher.INSTANCE;
        } else if (xpath.length() == 0) {
            return ElementMatcher.INSTANCE;
        } else if (xpath.startsWith("/@")) {
            String name = xpath.substring(2);
            String prefix = null;
            int colon = name.indexOf(':');
            if (colon != -1) {
                prefix = name.substring(0, colon);
                name = name.substring(colon + 1);
            }
            if (prefixes.containsKey(prefix)) {
                return new NamedAttributeMatcher(prefixes.get(prefix), name);
            } else {
                return Matcher.FAIL;
            }
        } else if (xpath.startsWith("/*")) {
            return new ChildMatcher(parse(xpath.substring(2)));
        } else if (xpath.startsWith("///")) {
            return Matcher.FAIL;
        } else if (xpath.startsWith("//")) {
            return new SubtreeMatcher(parse(xpath.substring(1)));
        } else if (xpath.startsWith("/")) {
            int slash = xpath.indexOf('/', 1);
            if (slash == -1) {
                slash = xpath.length();
            }
            String name = xpath.substring(1, slash);
            String prefix = null;
            int colon = name.indexOf(':');
            if (colon != -1) {
                prefix = name.substring(0, colon);
                name = name.substring(colon + 1);
            }
            if (prefixes.containsKey(prefix)) {
                return new NamedElementMatcher(prefixes.get(prefix), name,
                        parse(xpath.substring(slash)));
            } else {
                return Matcher.FAIL;
            }
        } else {
            return Matcher.FAIL;
        }
    }
@Test
    public void testPrefixedElement() {
        Matcher matcher = parser.parse("/prefix:name");
        assertFalse(matcher.matchesText());
        assertFalse(matcher.matchesElement());
        assertFalse(matcher.matchesAttribute(null, "name"));
        assertFalse(matcher.matchesAttribute(NS, "name"));
        assertFalse(matcher.matchesAttribute(NS, "eman"));
        assertEquals(Matcher.FAIL, matcher.descend(null, "name"));
        assertEquals(Matcher.FAIL, matcher.descend(NS, "enam"));
        matcher = matcher.descend(NS, "name");
        assertFalse(matcher.matchesText());
        assertTrue(matcher.matchesElement());
        assertFalse(matcher.matchesAttribute(null, "name"));
        assertFalse(matcher.matchesAttribute(NS, "name"));
        assertFalse(matcher.matchesAttribute(NS, "eman"));
    }