Show XPath location of an error
git-svn-id: https://svn.apache.org/repos/asf/maven/maven-1/plugins/trunk@306542 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
652d1a563d
commit
f0167d57a5
@ -17,22 +17,25 @@ package org.apache.maven;
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
|
||||
import com.sun.msv.verifier.jaxp.SAXParserFactoryImpl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import javax.xml.parsers.*;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import org.iso_relax.verifier.Verifier;
|
||||
import org.iso_relax.verifier.VerifierFactory;
|
||||
import org.iso_relax.verifier.VerifierHandler;
|
||||
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
* JaxpMsvBean Bean: Uses JAXP implementation of MSV.
|
||||
@ -52,86 +55,47 @@ public class JaxpMsvBean
|
||||
/** For debug output. */
|
||||
private Log log = LogFactory.getLog(JaxpMsvBean.class);
|
||||
|
||||
private static String EMPTY = "";
|
||||
private static ByteArrayInputStream EMPTY_STREAM =
|
||||
private static final String EMPTY = "";
|
||||
private static final ByteArrayInputStream EMPTY_STREAM =
|
||||
new ByteArrayInputStream(EMPTY.getBytes());
|
||||
|
||||
private static int MSV_WARNING = 0;
|
||||
private static int MSV_ERROR = 1;
|
||||
private static int MSV_FATAL_ERROR = 2;
|
||||
private static final int MSV_WARNING = 0;
|
||||
private static final int MSV_ERROR = 1;
|
||||
private static final int MSV_FATAL_ERROR = 2;
|
||||
|
||||
private boolean isValid = true;
|
||||
private XPathLocationTracker tracker;
|
||||
|
||||
//~ Methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Performs validation.
|
||||
* @throws Exception Exception
|
||||
*/
|
||||
public void validate() throws Exception
|
||||
{
|
||||
SAXParserFactory factory =
|
||||
new SAXParserFactoryImpl(new File(schema));
|
||||
|
||||
VerifierFactory verifierFactory =
|
||||
new com.sun.msv.verifier.jarv.TheFactoryImpl();
|
||||
Verifier verifier = verifierFactory.newVerifier(new File(schema));
|
||||
|
||||
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
parser.parse(new File(file), new DefaultHandler()
|
||||
{
|
||||
boolean isValid = true;
|
||||
public void warning(SAXParseException e) throws SAXException
|
||||
{
|
||||
errorMessage(e, MSV_WARNING);
|
||||
}
|
||||
public void error(SAXParseException e) throws SAXException
|
||||
{
|
||||
errorMessage(e, MSV_ERROR);
|
||||
isValid = false;
|
||||
}
|
||||
public void fatalError(SAXParseException e) throws SAXException
|
||||
{
|
||||
errorMessage(e, MSV_FATAL_ERROR);
|
||||
isValid = false;
|
||||
}
|
||||
public InputSource resolveEntity(String publicId,
|
||||
String systemId) throws SAXException
|
||||
{
|
||||
log.warn("WARNING: External entity " + systemId
|
||||
+ " won't be resolved!");
|
||||
return new InputSource(EMPTY_STREAM);
|
||||
}
|
||||
public void endDocument()
|
||||
{
|
||||
if(isValid)
|
||||
{
|
||||
log.info(file + " verified: OK");
|
||||
} else {
|
||||
log.info("WARNING: " + file + " is NOT valid");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
XMLReader reader = factory.newSAXParser().getXMLReader();
|
||||
|
||||
private void errorMessage(SAXParseException e, int type)
|
||||
{
|
||||
File xmlFile = new File(file);
|
||||
VerifierHandler handler = verifier.getVerifierHandler();
|
||||
tracker = new XPathLocationTracker(handler);
|
||||
reader.setContentHandler(tracker);
|
||||
reader.setEntityResolver( new EntityResolverImpl() );
|
||||
verifier.setErrorHandler( new ErrorHandlerImpl() );
|
||||
|
||||
if (type == MSV_ERROR)
|
||||
{
|
||||
log.error( "com.sun.msv.verifier.ValidityViolation on line "
|
||||
+ e.getLineNumber() + " of " + xmlFile.getName() + ":" );
|
||||
log.error( e.getMessage() );
|
||||
} else if (type == MSV_FATAL_ERROR)
|
||||
{
|
||||
log.error( "Non-recoverable parsing error on line "
|
||||
+ e.getLineNumber() + " of " + xmlFile.getName() + ":" );
|
||||
log.error( e.getMessage() );
|
||||
} else if (type == MSV_WARNING)
|
||||
{
|
||||
log.warn( "Warning on line "
|
||||
+ e.getLineNumber() + " of " + xmlFile.getName() + ":" );
|
||||
log.warn( e.getMessage() );
|
||||
}
|
||||
reader.parse(new InputSource(new FileInputStream(file)));
|
||||
endMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the schema.
|
||||
*
|
||||
* @param newSchema The schema to set
|
||||
*/
|
||||
public void setSchema(String newSchema)
|
||||
@ -141,7 +105,6 @@ public class JaxpMsvBean
|
||||
|
||||
/**
|
||||
* Sets the file.
|
||||
*
|
||||
* @param newFile The file to set
|
||||
*/
|
||||
public void setFile(String newFile)
|
||||
@ -151,7 +114,6 @@ public class JaxpMsvBean
|
||||
|
||||
/**
|
||||
* Gets the schema.
|
||||
*
|
||||
* @return The schema
|
||||
*/
|
||||
public String getSchema()
|
||||
@ -161,7 +123,6 @@ public class JaxpMsvBean
|
||||
|
||||
/**
|
||||
* Gets the file.
|
||||
*
|
||||
* @return The file
|
||||
*/
|
||||
public String getFile()
|
||||
@ -169,5 +130,76 @@ public class JaxpMsvBean
|
||||
return file;
|
||||
}
|
||||
|
||||
private void endMessage()
|
||||
{
|
||||
if ( isValid )
|
||||
{
|
||||
log.info(file + " verified: OK");
|
||||
} else {
|
||||
log.info(file + " is NOT valid!");
|
||||
}
|
||||
}
|
||||
|
||||
private void setValid(boolean valid)
|
||||
{
|
||||
this.isValid = valid;
|
||||
}
|
||||
|
||||
private void errorMessage(SAXParseException e, int type)
|
||||
{
|
||||
File xmlFile = new File(file);
|
||||
|
||||
if (type == MSV_ERROR)
|
||||
{
|
||||
log.error( " ERROR on line " + e.getLineNumber()
|
||||
+ " of file " + xmlFile.getName() + "," );
|
||||
log.error( " XPath location " + tracker.getXPath() + ":" );
|
||||
log.error( " " + e.getMessage() );
|
||||
} else if (type == MSV_FATAL_ERROR)
|
||||
{
|
||||
log.error( " Non-recoverable parsing error on line "
|
||||
+ e.getLineNumber() + " of file " + xmlFile.getName() + "," );
|
||||
log.error( " XPath location " + tracker.getXPath() + ":" );
|
||||
log.error( " " + e.getMessage() );
|
||||
} else if (type == MSV_WARNING)
|
||||
{
|
||||
log.warn( " WARNING on line " + e.getLineNumber()
|
||||
+ " of file " + xmlFile.getName() + "," );
|
||||
log.warn( " XPath location " + tracker.getXPath() + ":" );
|
||||
log.warn( e.getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
private class ErrorHandlerImpl implements ErrorHandler
|
||||
{
|
||||
public void warning(SAXParseException e) throws SAXException
|
||||
{
|
||||
errorMessage(e, MSV_WARNING);
|
||||
}
|
||||
|
||||
public void error(SAXParseException e) throws SAXException
|
||||
{
|
||||
errorMessage(e, MSV_ERROR);
|
||||
setValid(false);
|
||||
}
|
||||
|
||||
public void fatalError(SAXParseException e) throws SAXException
|
||||
{
|
||||
errorMessage(e, MSV_FATAL_ERROR);
|
||||
setValid(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class EntityResolverImpl implements EntityResolver
|
||||
{
|
||||
public InputSource resolveEntity(String publicId,
|
||||
String systemId) throws SAXException
|
||||
{
|
||||
log.warn(" WARNING: External entity " + systemId
|
||||
+ " won't be resolved");
|
||||
return new InputSource(EMPTY_STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
206
plugin/src/main/org/apache/maven/XPathLocationTracker.java
Normal file
206
plugin/src/main/org/apache/maven/XPathLocationTracker.java
Normal file
@ -0,0 +1,206 @@
|
||||
package org.apache.maven;
|
||||
|
||||
/* ====================================================================
|
||||
* Copyright 2001-2005 The Apache Software Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
/**
|
||||
* Constructs an XPath expression in the form:
|
||||
* /root/child[3]/grandchild[2] ...
|
||||
*
|
||||
* @author <a href="mailto:ltheussl@apache.org">Lukas Theussl</a>
|
||||
*/
|
||||
|
||||
public class XPathLocationTracker extends XMLFilterImpl
|
||||
{
|
||||
|
||||
private State state;
|
||||
private static final Integer[] ints = new Integer[]
|
||||
{
|
||||
new Integer(0),
|
||||
new Integer(1),
|
||||
new Integer(2),
|
||||
new Integer(3),
|
||||
new Integer(4)
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor: sets the ContentHandler.
|
||||
* @param handler The ContentHandler
|
||||
*/
|
||||
public XPathLocationTracker( ContentHandler handler )
|
||||
{
|
||||
setContentHandler(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding ContentHandler.
|
||||
* @throws SAXException SAXException
|
||||
*/
|
||||
public void startDocument() throws SAXException
|
||||
{
|
||||
state = new State(null);
|
||||
super.startDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding ContentHandler.
|
||||
* @throws SAXException SAXException
|
||||
*/
|
||||
public void endDocument() throws SAXException
|
||||
{
|
||||
super.endDocument();
|
||||
state = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding ContentHandler.
|
||||
* @param uri uri
|
||||
* @param localName localName
|
||||
* @param qName qName
|
||||
* @param atts atts
|
||||
* @throws SAXException SAXException
|
||||
*/
|
||||
public void startElement(String uri, String localName,
|
||||
String qName, Attributes atts) throws SAXException
|
||||
{
|
||||
state = state.push(qName);
|
||||
super.startElement(uri, localName, qName, atts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding ContentHandler.
|
||||
* @param uri uri
|
||||
* @param localName localName
|
||||
* @param qName qName
|
||||
* @throws SAXException SAXException
|
||||
*/
|
||||
public void endElement(String uri, String localName, String qName)
|
||||
throws SAXException
|
||||
{
|
||||
super.endElement(uri, localName, qName);
|
||||
state = state.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the XPath expression that points to the current location.
|
||||
* Throws a new IllegalStateException if the component is not
|
||||
* parsing a document.
|
||||
* @return The XPath expression
|
||||
*/
|
||||
public final String getXPath()
|
||||
{
|
||||
if ( state == null )
|
||||
{
|
||||
throw new IllegalStateException(
|
||||
"startDocument event is not invoked");
|
||||
}
|
||||
return state.getXPath();
|
||||
}
|
||||
|
||||
private static Integer getInt(int i)
|
||||
{
|
||||
if ( i < ints.length )
|
||||
{
|
||||
return ints[i];
|
||||
} else {
|
||||
return new Integer(i);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class State
|
||||
{
|
||||
|
||||
private final Map counter = new HashMap();
|
||||
private final State parent;
|
||||
private State child;
|
||||
private String currentName;
|
||||
|
||||
State( State newParent )
|
||||
{
|
||||
this.parent = newParent;
|
||||
}
|
||||
|
||||
protected State push( String rawName )
|
||||
{
|
||||
count(rawName);
|
||||
currentName = rawName;
|
||||
if ( child == null )
|
||||
{
|
||||
child = new State(this);
|
||||
} else {
|
||||
child.reset();
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
protected State pop()
|
||||
{
|
||||
parent.currentName = null;
|
||||
return parent;
|
||||
}
|
||||
|
||||
private void count( String rawName )
|
||||
{
|
||||
Integer i = (Integer) counter.get(rawName);
|
||||
if ( i == null )
|
||||
{
|
||||
i = getInt(1);
|
||||
} else {
|
||||
i = getInt(i.intValue() + 1);
|
||||
}
|
||||
counter.put(rawName, i);
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
counter.clear();
|
||||
currentName = null;
|
||||
}
|
||||
|
||||
private String getXPath()
|
||||
{
|
||||
String xPath;
|
||||
if ( parent == null ) // root
|
||||
{
|
||||
xPath = "/";
|
||||
if ( currentName != null)
|
||||
{
|
||||
xPath += currentName;
|
||||
}
|
||||
} else { // child node
|
||||
xPath = parent.getXPath();
|
||||
if ( currentName != null )
|
||||
{
|
||||
xPath += '/' + currentName;
|
||||
Integer i = (Integer) counter.get(currentName);
|
||||
xPath += '[' + i.toString() + ']';
|
||||
}
|
||||
}
|
||||
return xPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user