/* * Copyright (c) 1998-2000 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson * * $Id: Navigation.java,v 1.2 2004/09/29 00:13:49 cvs Exp $ */ package com.caucho.web; import com.caucho.util.Tree; import com.caucho.vfs.Path; import com.caucho.xml.LooseXml; import com.caucho.xpath.Env; import com.caucho.xpath.Expr; import com.caucho.xpath.XPath; import com.caucho.xpath.XPathFun; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import java.util.ArrayList; import java.util.Iterator; public class Navigation { private Element root; private String base; private Tree tree; public Navigation() { } public Navigation(Path path, String base) throws Exception { Document doc = new LooseXml().parseDocument(path); init(doc.getDocumentElement(), base); } public Navigation(Env env, Path path, String base) throws Exception { Document doc = new LooseXml().parseDocument(path); init(env, doc.getDocumentElement(), base); } /** * Create a new navigation structure. * * @param root the top of the navigation */ public Navigation(Env env, Element root, String base) throws Exception { init(env, root, base); } public Navigation(Element root, String base) throws Exception { init(root, base); } public void init(Element root, String base) throws Exception { init(null,root,base); } public void init(Env env, Element root, String base) throws Exception { tree = new Tree(null); this.root = root; if (base == null || base == "") base = "/"; this.base = base; if (root != null) fillChildren(env, tree, root.getFirstChild(), base); } public static Navigation createNested(Path pwd, String base) throws Exception { return createNested(null,pwd,base); } public static Navigation createNested(Env env, Path pwd, String base) throws Exception { Navigation baseNav = null; Navigation subNav = null; if (base.startsWith("/")) base = base.substring(1); String dir = base; while (true) { Path path = pwd.lookup(dir).lookup("toc.xml"); Navigation nav = null; if (path.exists()) nav = new Navigation(env, path, dir); if (baseNav == null) baseNav = nav; else if (nav != null) baseNav.linkParent(nav); if (dir.equals("")) break; int p; if (dir.endsWith("/")) { p = dir.lastIndexOf('/', dir.length() - 2); } else p = dir.lastIndexOf('/'); if (p <= 0) dir = ""; else dir = dir.substring(0, p + 1); } return baseNav; } public static Navigation createNested(ArrayList paths, String base) throws Exception { return createNested(null,paths,base); } public static Navigation createNested(Env env, ArrayList paths, String base) throws Exception { Navigation baseNav = null; Navigation subNav = null; if (base.startsWith("/")) base = base.substring(1); String dir = base; for (int i = 0; i < paths.size(); i++) { Path path = ((Path) paths.get(i)).lookup("toc.xml"); Navigation nav = null; if (path.exists()) nav = new Navigation(env, path, dir); if (baseNav == null) baseNav = nav; else if (nav != null) baseNav.linkParent(nav); if (dir.equals("")) break; int p; if (dir.endsWith("/")) { p = dir.lastIndexOf('/', dir.length() - 2); } else p = dir.lastIndexOf('/'); if (p <= 0) dir = ""; else dir = dir.substring(0, p + 1); } return baseNav; } public Navigation linkParent(Navigation parent) { if (tree == null) { tree = parent.tree; return this; } if (tree.getFirst() == null) return this; NavItem test = (NavItem) tree.getFirst().getData(); NavItem link = parent.findURL(test.getLink()); if (link == null) return null; Tree parentTree = link.getTree(); linkTree(link.getTree(), tree.getFirst()); this.tree = parent.tree; return this; } /** * Attaches the child tree in its proper location in the dest tree * * @param destTree parent tree * @param subTree child tree */ private void linkTree(Tree destTree, Tree subTree) { for (Tree child = subTree.getFirst(); child != null; child = child.getNext()) { NavItem item = (NavItem) child.getData(); Tree childTree = destTree.append(item); item.setTree(childTree); linkTree(childTree, child); } } /** * Returns an attribute from the top-level navigation element. * * @param name The name of the attribute. */ public String getAttribute(String name) { if (root == null) return ""; return root.getAttribute(name); } /** * @param url the url to match */ public NavItem findURL(String url) { if (tree == null) return null; url = normalizeURL(url); Iterator iter = tree.dfs(); while (iter.hasNext()) { Tree tree = (Tree) iter.next(); NavItem item = (NavItem) tree.getData(); if (item.getLink().equals(url)) { return item; } } return null; } /** */ private void fillChildren(Env env, Tree tree, Node childNode, String base) throws Exception { XPathFun docShouldDisplay = env == null ? null : env.getFunction("doc-should-display"); for (; childNode != null; childNode = childNode.getNextSibling()) { if (! childNode.getNodeName().equals("item")) continue; if (docShouldDisplay != null && !Expr.toBoolean(docShouldDisplay.eval(childNode,env,null,null))) continue; Element elt = (Element) childNode; NavItem item = new NavItem(); String href = linkPattern.evalString(elt); item.setLink(resolveURL(href, childNode, base)); item.setTitle(titlePattern.evalString(elt)); String desc; desc = descPattern.evalString(elt); item.setDescription(desc); item.setProduct(_productPattern.evalString(elt)); Tree childTree = tree.append(item); item.setTree(childTree); fillChildren(env, childTree, childNode.getFirstChild(), base); } } private String resolveURL(String url, Node node, String base) { if (url.length() == 0) return "/"; if (url.startsWith("http:") || url.charAt(0) == '/') return url; // normalizeURL(url); for (; node instanceof Element; node = node.getParentNode()) { Element elt = (Element) node; String nodeBase = elt.getAttribute("xml:base"); if (nodeBase.equals("")) continue; if (! nodeBase.endsWith("/")) return resolveURL(nodeBase + "/" + url, elt.getParentNode(), base); else return resolveURL(nodeBase + url, elt.getParentNode(), base); } if (! base.endsWith("/")) return normalizeURL(base + "/" + url); else return normalizeURL(base + url); } private String normalizeURL(String url) { if (url.startsWith("/")) return url; else if (url.startsWith("http://")) return url; else return "/" + url; /* int i; for (i = "http://".length(); i < url.length(); i++) { if (url.charAt(i) == '/') { return url.substring(i); } } return "/"; */ } static Expr linkPattern; static Expr titlePattern; static Expr descPattern; static Expr _productPattern; static { try { linkPattern = XPath.parseExpr("if(@link,@link,link)"); titlePattern = XPath.parseExpr("if(@title,@title,title)"); descPattern = XPath.parseExpr("if(@description,@description,description)"); _productPattern = XPath.parseExpr("if(@product,@product,product)"); } catch (Exception e) { } } }