| /******************************************************************************* |
| * Copyright (c) 2004, 2006 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - Initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.wst.xml.core.internal.search.quickscan; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Stack; |
| |
| import org.eclipse.wst.common.core.search.document.ComponentDeclarationEntry; |
| import org.eclipse.wst.common.core.search.document.ComponentReferenceEntry; |
| import org.eclipse.wst.common.core.search.document.FileReferenceEntry; |
| import org.eclipse.wst.common.core.search.document.SearchDocument; |
| import org.eclipse.wst.common.core.search.pattern.QualifiedName; |
| import org.eclipse.wst.common.core.search.pattern.SearchPattern; |
| import org.eclipse.wst.xml.core.internal.search.XMLComponentDeclarationPattern; |
| import org.eclipse.wst.xml.core.internal.search.XMLComponentReferencePattern; |
| import org.eclipse.wst.xml.core.internal.search.impl.IXMLSearchConstants; |
| import org.eclipse.wst.xml.core.internal.search.matching.PatternMatcher; |
| import org.eclipse.wst.xml.core.internal.search.matching.SAXSearchElement; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| /** |
| * This class is a SAX content handler, it should be recycled before scanning a file for the new SearchPattern. |
| * |
| */ |
| public class XMLQuickScanContentHandler extends DefaultHandler |
| { |
| private Map namespaceMap = new HashMap(); // Map of string prefix keys and namespace |
| private String targetNamespace = ""; //$NON-NLS-1$ |
| |
| private SearchPattern pattern; |
| private SearchDocument document; // we'll add useful entries in the search document as we parsing |
| private SAXSearchElement searchElement = new SAXSearchElement(); |
| |
| private boolean hasMatch = false; |
| private Stack currentPath = new Stack(); |
| private PatternMatcher matcher; |
| |
| public static final String XMLSCHEMA_NAMESPACE = "http://www.w3.org/2001/XMLSchema"; //$NON-NLS-1$ |
| public static final String WSDL_NAMESPACE = "http://schemas.xmlsoap.org/wsdl/"; //$NON-NLS-1$ |
| |
| |
| public XMLQuickScanContentHandler(PatternMatcher matcher, SearchPattern pattern) { |
| super(); |
| this.pattern = pattern; |
| this.matcher = matcher; |
| } |
| |
| public XMLQuickScanContentHandler(SearchDocument document, PatternMatcher matcher, SearchPattern pattern) { |
| super(); |
| this.pattern = pattern; |
| this.matcher = matcher; |
| this.document = document; |
| } |
| |
| public XMLQuickScanContentHandler() { |
| super(); |
| } |
| |
| public void startElement(String uri, String localName, String qName, |
| Attributes attributes) throws SAXException |
| { |
| // Search for targetNamespace if we haven't encountered it yet. |
| if (targetNamespace.equals("")) //$NON-NLS-1$ |
| { |
| int nAttributes = attributes.getLength(); |
| for (int i = 0; i < nAttributes; i++) |
| { |
| if ("targetNamespace".equals(attributes.getQName(i))) //$NON-NLS-1$ |
| { |
| targetNamespace = attributes.getValue(i); |
| break; |
| } |
| } |
| } |
| |
| // collect link info |
| |
| // TODO This code should be refactored to delegate the responsibility to |
| // detect links between files to the search providers/contributors. |
| // The current code only handles the XSD and WSDL cases. |
| |
| if("import".equals(localName) && namespaceMatches(uri)){ //$NON-NLS-1$ |
| FileReferenceEntry documentEntry = new FileReferenceEntry(); |
| documentEntry.setCategory(IXMLSearchConstants.REF); |
| documentEntry.setKey("import"); //$NON-NLS-1$ |
| String namespace = attributes.getValue("namespace"); //$NON-NLS-1$ |
| String location = attributes.getValue(getLocationAttributeName(uri)); //$NON-NLS-1$ |
| documentEntry.setPublicIdentifier(namespace); |
| documentEntry.setRelativeFilePath(location); |
| document.putEntry(documentEntry); |
| } |
| if(("redefine".equals(localName)|| "include".equals(localName)) && //$NON-NLS-1$ //$NON-NLS-2$ |
| namespaceMatches(uri)){ |
| FileReferenceEntry documentEntry = new FileReferenceEntry(); |
| documentEntry.setCategory(IXMLSearchConstants.REF); |
| documentEntry.setKey("include"); //$NON-NLS-1$ |
| String location = attributes.getValue(getLocationAttributeName(uri)); //$NON-NLS-1$ |
| documentEntry.setPublicIdentifier(uri); |
| documentEntry.setRelativeFilePath(location); |
| document.putEntry(documentEntry); |
| } |
| |
| |
| // issue (cs) you may want to try perf measurements to compate reusing the same |
| // instance of a SAXSearchElement instead of newing one each time |
| //XMLSearchPattern.SAXSearchElement searchElement = new XMLSearchPattern.SAXSearchElement(); |
| searchElement.setElementName(localName); |
| searchElement.setElementNamespace(uri); |
| searchElement.setAttributes(attributes); |
| searchElement.setNamespaceMap(namespaceMap); |
| searchElement.setTargetNamespace(targetNamespace); |
| if (currentPath.size() > 0) |
| { |
| String parentName = (String)currentPath.peek(); |
| searchElement.setParentName(parentName); |
| } |
| |
| |
| if(matcher != null){ |
| if(matcher.matches(pattern, searchElement)){ |
| hasMatch = true; |
| if(pattern instanceof XMLComponentReferencePattern){ |
| ComponentReferenceEntry documentEntry = new ComponentReferenceEntry(); |
| documentEntry.setCategory(IXMLSearchConstants.COMPONENT_REF); |
| QualifiedName name = new QualifiedName(uri, localName); |
| documentEntry.setKey(name.toString()); |
| documentEntry.setName(name); |
| document.putEntry(documentEntry); |
| } |
| else if(pattern instanceof XMLComponentDeclarationPattern){ |
| ComponentDeclarationEntry documentEntry = new ComponentDeclarationEntry(); |
| documentEntry.setCategory(IXMLSearchConstants.COMPONENT_DECL); |
| QualifiedName name = new QualifiedName(targetNamespace, attributes.getValue("name")); //$NON-NLS-1$ |
| QualifiedName metaName = new QualifiedName(uri, localName); |
| documentEntry.setKey(name.toString()); |
| documentEntry.setName(name); |
| documentEntry.setMetaName(metaName); |
| document.putEntry(documentEntry); |
| } |
| } |
| } |
| currentPath.push(localName); //$NON-NLS-1$ |
| } |
| |
| private String getLocationAttributeName(String uri) |
| { |
| if (XMLSCHEMA_NAMESPACE.equals(uri)) |
| { |
| return "schemaLocation"; |
| } |
| |
| else if (WSDL_NAMESPACE.equals(uri)) |
| { |
| return "location"; |
| } |
| |
| return ""; |
| } |
| |
| private boolean namespaceMatches(String uri) |
| { |
| return XMLSCHEMA_NAMESPACE.equals(uri) || |
| WSDL_NAMESPACE.equals(uri); |
| } |
| |
| public void endElement(String uri, String localName, String qName) |
| throws SAXException |
| { |
| currentPath.pop(); |
| } |
| |
| /** |
| * Callback for SAX parser |
| * |
| * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, |
| * java.lang.String) |
| */ |
| public void startPrefixMapping(String arg0, String arg1) |
| throws SAXException |
| { |
| if (arg0 != null && arg0.length() > 0) |
| { |
| this.namespaceMap.put(arg0, arg1); |
| } |
| } |
| |
| public String getTargetNamespace() { |
| return targetNamespace; |
| } |
| |
| public void setTargetNamespace(String targetNamespace) { |
| this.targetNamespace = targetNamespace; |
| } |
| |
| public boolean hasMatch() { |
| return hasMatch; |
| } |
| |
| |
| } |