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.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
|
||||||
import javax.xml.parsers.*;
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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.SAXParseException;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.XMLReader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JaxpMsvBean Bean: Uses JAXP implementation of MSV.
|
* JaxpMsvBean Bean: Uses JAXP implementation of MSV.
|
||||||
@ -52,86 +55,47 @@ public class JaxpMsvBean
|
|||||||
/** For debug output. */
|
/** For debug output. */
|
||||||
private Log log = LogFactory.getLog(JaxpMsvBean.class);
|
private Log log = LogFactory.getLog(JaxpMsvBean.class);
|
||||||
|
|
||||||
private static String EMPTY = "";
|
private static final String EMPTY = "";
|
||||||
private static ByteArrayInputStream EMPTY_STREAM =
|
private static final ByteArrayInputStream EMPTY_STREAM =
|
||||||
new ByteArrayInputStream(EMPTY.getBytes());
|
new ByteArrayInputStream(EMPTY.getBytes());
|
||||||
|
|
||||||
private static int MSV_WARNING = 0;
|
private static final int MSV_WARNING = 0;
|
||||||
private static int MSV_ERROR = 1;
|
private static final int MSV_ERROR = 1;
|
||||||
private static int MSV_FATAL_ERROR = 2;
|
private static final int MSV_FATAL_ERROR = 2;
|
||||||
|
|
||||||
|
private boolean isValid = true;
|
||||||
|
private XPathLocationTracker tracker;
|
||||||
|
|
||||||
//~ Methods --------------------------------------------------------------
|
//~ Methods --------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs validation.
|
* Performs validation.
|
||||||
|
* @throws Exception Exception
|
||||||
*/
|
*/
|
||||||
public void validate() throws 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);
|
factory.setNamespaceAware(true);
|
||||||
SAXParser parser = factory.newSAXParser();
|
XMLReader reader = factory.newSAXParser().getXMLReader();
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void errorMessage(SAXParseException e, int type)
|
VerifierHandler handler = verifier.getVerifierHandler();
|
||||||
{
|
tracker = new XPathLocationTracker(handler);
|
||||||
File xmlFile = new File(file);
|
reader.setContentHandler(tracker);
|
||||||
|
reader.setEntityResolver( new EntityResolverImpl() );
|
||||||
|
verifier.setErrorHandler( new ErrorHandlerImpl() );
|
||||||
|
|
||||||
if (type == MSV_ERROR)
|
reader.parse(new InputSource(new FileInputStream(file)));
|
||||||
{
|
endMessage();
|
||||||
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() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the schema.
|
* Sets the schema.
|
||||||
*
|
|
||||||
* @param newSchema The schema to set
|
* @param newSchema The schema to set
|
||||||
*/
|
*/
|
||||||
public void setSchema(String newSchema)
|
public void setSchema(String newSchema)
|
||||||
@ -141,7 +105,6 @@ public class JaxpMsvBean
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the file.
|
* Sets the file.
|
||||||
*
|
|
||||||
* @param newFile The file to set
|
* @param newFile The file to set
|
||||||
*/
|
*/
|
||||||
public void setFile(String newFile)
|
public void setFile(String newFile)
|
||||||
@ -151,7 +114,6 @@ public class JaxpMsvBean
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the schema.
|
* Gets the schema.
|
||||||
*
|
|
||||||
* @return The schema
|
* @return The schema
|
||||||
*/
|
*/
|
||||||
public String getSchema()
|
public String getSchema()
|
||||||
@ -161,7 +123,6 @@ public class JaxpMsvBean
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the file.
|
* Gets the file.
|
||||||
*
|
|
||||||
* @return The file
|
* @return The file
|
||||||
*/
|
*/
|
||||||
public String getFile()
|
public String getFile()
|
||||||
@ -169,5 +130,76 @@ public class JaxpMsvBean
|
|||||||
return file;
|
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