77import java .util .regex .PatternSyntaxException ;
88
99import javax .xml .XMLConstants ;
10+ import javax .xml .bind .DatatypeConverter ;
1011
1112import org .slf4j .Logger ;
1213import org .slf4j .LoggerFactory ;
@@ -51,6 +52,7 @@ private static enum ElementNames {
5152
5253 private static final String CUSTOM_NAME_FORMAT_ATTR = "customNameFormat" ;
5354
55+ private static final String FILENAME_FILTER_MATCH_LOCAL_ATTR = "matchLocalFileNameOnly" ;
5456 private static final String GROUP_NUMBER_ATTR = "group" ;
5557 private static final String KEY_XPATH_ATTR = "keyXPath" ;
5658 private static final String KVPAIR_ROOT_XPATH_ATTR = "kvPairRoot" ;
@@ -322,13 +324,38 @@ private void endMappingList() {
322324 }
323325 }
324326
327+ /**
328+ * Retrieve an attribute value cast as a Boolean, according the rules specified by XSD spec ({@link DatatypeConverter#parseBoolean(String)}).
329+ *
330+ * @param atts the set of of attributes to retrieve from.
331+ * @param attrName the name of the attribute to retrieve.
332+ * @return true or false, depending on the value of the attribute, as per the XSD spec.
333+ * @throws SAXException if the value specified by <code>attrName</code> is present but not valid according to the XSD spec for XSD boolean value
334+ * types.
335+ */
336+ private boolean getAttributeValueAsBoolean (Attributes atts , String attrName ) throws SAXException {
337+ String attrValueAsString = atts .getValue (attrName );
338+ if (attrValueAsString == null ) {
339+ return false ;
340+ } else {
341+ try {
342+ boolean parsedBoolean = DatatypeConverter .parseBoolean (attrValueAsString );
343+ LOG .trace ("Parsed {} value {} as {}" , attrName , attrValueAsString , parsedBoolean );
344+ return parsedBoolean ;
345+ } catch (IllegalArgumentException iae ) {
346+ // Thrown by DatatypeConverter.parseBoolean for an invalid argument
347+ throw getException (iae , "Invalid value \" %s\" found in attriute \" %s\" " , attrValueAsString , attrName );
348+ }
349+ }
350+ }
351+
325352 /**
326353 * Retrieve an attribute value cast as an Integer, null if one wasn't specified, or throw an exception if malformed.
327354 *
328355 * @param atts the set of of attributes to retrieve from.
329356 * @param attrName the name of the attribute to retrieve.
330- * @return the value retrieved, or value in <code>defaultValue </code> if a value could not be found .
331- * @throws SAXException thrown if the value found in the attribute is an integer.
357+ * @return an integer value of the value in <code>attrName </code>, null if no value was specified .
358+ * @throws SAXException thrown if the value found in the attribute is not an integer.
332359 */
333360 private Integer getAttributeValueAsInteger (Attributes atts , String attrName ) throws SAXException {
334361 String attrValueAsString = atts .getValue (attrName );
@@ -343,27 +370,6 @@ private Integer getAttributeValueAsInteger(Attributes atts, String attrName) thr
343370 }
344371 }
345372
346- /**
347- * Gets a list of the known child names of the parent container. These are used as variable names, available in the XPath evaluation of subsequent
348- * mappings with the same parent.
349- * @return an array, possibly empty, of known siblings of the current mapping (as determined by the top of {@link #mappingListStack}.
350- */
351- private String [] getPreviousSiblingNames () {
352- List <String > variables = new ArrayList <String >();
353- MappingList currentContainer = this .mappingListStack .peek ();
354- for (IMapping m : currentContainer ) {
355- if (m instanceof IValueMapping ) {
356- IValueMapping vm = (IValueMapping ) m ;
357- variables .add (vm .getName ());
358- }
359- }
360- String [] varArray = variables .toArray (new String [0 ]);
361- if (LOG .isDebugEnabled ()) {
362- LOG .debug ("Created variable set for {}: {}" , currentContainer .getName (), StringUtil .toStringList (varArray ));
363- }
364- return varArray ;
365- }
366-
367373 /**
368374 * Given an element's local name (namespace URI checking is left to the caller), return an enum value that can be used in switch statements to
369375 * branch logic depending on the input.
@@ -393,9 +399,8 @@ private ElementNames getElementNameEnum(String localName) throws SAXException {
393399 */
394400 private SAXException getException (Exception inner , String message , Object ... parameters ) {
395401 String temp = String .format (message , parameters );
396- XMLException de =
397- new XMLException (inner , "Error parsing %s(%d:%d) %s" , this .documentLocator .getSystemId (),
398- this .documentLocator .getLineNumber (), this .documentLocator .getColumnNumber (), temp );
402+ XMLException de = new XMLException (inner , "Error parsing %s(%d:%d) %s" , this .documentLocator .getSystemId (),
403+ this .documentLocator .getLineNumber (), this .documentLocator .getColumnNumber (), temp );
399404 SAXException se = new SAXException (de );
400405 return se ;
401406 }
@@ -409,6 +414,28 @@ public MappingConfiguration getMappings() {
409414 return this .mappingConfiguration ;
410415 }
411416
417+ /**
418+ * Gets a list of the known child names of the parent container. These are used as variable names, available in the XPath evaluation of subsequent
419+ * mappings with the same parent.
420+ *
421+ * @return an array, possibly empty, of known siblings of the current mapping (as determined by the top of {@link #mappingListStack}.
422+ */
423+ private String [] getPreviousSiblingNames () {
424+ List <String > variables = new ArrayList <String >();
425+ MappingList currentContainer = this .mappingListStack .peek ();
426+ for (IMapping m : currentContainer ) {
427+ if (m instanceof IValueMapping ) {
428+ IValueMapping vm = (IValueMapping ) m ;
429+ variables .add (vm .getName ());
430+ }
431+ }
432+ String [] varArray = variables .toArray (new String [0 ]);
433+ if (LOG .isDebugEnabled ()) {
434+ LOG .debug ("Created variable set for {}: {}" , currentContainer .getName (), StringUtil .toStringList (varArray ));
435+ }
436+ return varArray ;
437+ }
438+
412439 @ Override
413440 public void setDocumentLocator (Locator locator ) {
414441 this .documentLocator = locator ;
@@ -466,7 +493,7 @@ public void startElement(String uri, String localName, String qName, Attributes
466493 startXPathFilter (atts .getValue ("xPath" ));
467494 break ;
468495 case FileNameInputFilter :
469- startFileNameFilter (atts .getValue ("fileNameRegex" ));
496+ startFileNameFilter (atts .getValue ("fileNameRegex" ), getAttributeValueAsBoolean ( atts , FILENAME_FILTER_MATCH_LOCAL_ATTR ) );
470497 break ;
471498 default :
472499 LOG .warn ("Ignoring element ({}):{} as it isn't supported in this version of xml2csv" , uri , localName );
@@ -480,11 +507,13 @@ public void startElement(String uri, String localName, String qName, Attributes
480507 * Adds filters to the mapping configuration.
481508 *
482509 * @param fileNameRegex a regular expression to match against the filename. May be null.
510+ * @param matchLocalFileNameOnly if false then the filter must match the absolute path name, if true then only the file name (no directory
511+ * information) will be used.
483512 * @throws SAXException If any errors occur whilst adding the filters.
484513 */
485- private void startFileNameFilter (String fileNameRegex ) throws SAXException {
514+ private void startFileNameFilter (String fileNameRegex , boolean matchLocalFileNameOnly ) throws SAXException {
486515 try {
487- IInputFilter filter = new FileNameInputFilter (fileNameRegex );
516+ IInputFilter filter = new FileNameInputFilter (fileNameRegex , matchLocalFileNameOnly );
488517 addFilter (filter );
489518 } catch (PatternSyntaxException pse ) {
490519 throw getException (pse , "Invalid Regular Expression {} specified for input filter." , fileNameRegex );
0 commit comments