Example: Recursive Search

www.altova.com Print this Topic Previous Page Up One Level Next page

Home >  Functions > User-Defined Functions >

Example: Recursive Search

This example illustrates a mapping that searches for data in a source XML file with the help of a recursive user-defined function. The mapping file is available at the following path: <Documents>\Altova\MapForce2019\MapForceExamples\RecursiveDirectoryFilter.mfd.

mf_udf_22

RecursiveDirectoryFilter.mfd

The source XML file contains information about files and directories, as illustrated by the code listing below (note that the listing omits some data for simplicity):

 

<?xml version="1.0" encoding="UTF-8"?>
<directory name="Examples">
  <directory name="ExampleSite">
    <file name="blocks.sps" size="7473"/>    
    <file name="block_file.xml" size="992"/>
    <directory name="output">
        <file name="examplesite1.css" size="3174"/>
        <directory name="images">
          <file name="blank.gif" size="88"/>
          <file name="block_file.gif" size="13179"/>          
        </directory>
    </directory>
  </directory>  
</directory>

Source XML file

Both the source and the target XML files use the same schema, Directory.xsd. Since, on a file system, a directory can contain either a file or another directory, this is also reflected in the schema. Importantly, the schema specifies that the directory element is recursive (see the line <xs:element ref="directory"/>).

 

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:element name="directory">
    <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="file">
              <xs:complexType>
                <xs:attribute name="name" type="xs:string"/>
                <xs:attribute name="size" type="xs:unsignedLong"/>
              </xs:complexType>
          </xs:element>
          <xs:element ref="directory"/>
        </xs:choice>
        <xs:attribute name="name"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

Directory.xsd

The business requirement of the mapping is to filter out only files with a specific extension. The nested structure of all directories must be preserved. For example, if extension is ".xml", the expected output (for the source XML file listed previously) should look as follows:

 

<?xml version="1.0" encoding="UTF-8"?>
<directory name="Examples">
  <directory name="ExampleSite">
    <file name="block_file.xml" size="992"/>
    <directory name="output">
        <directory name="images"/>
    </directory>
  </directory>
</directory>

Expected XML output

Secondly, callers of the mapping must be able to supply the file extension as a parameter. By default, if a caller does not supply a parameter value, the mapping will filter out files with .xml extension.

 

To address the requirements above, the mapping contains a simple input parameter, "SearchFor", which supplies the default file extension by means of a text constant. This parameter is optional (the Input is required check box is not selected in the Properties dialog box):

mf_udf_23

For more information about input parameters, see Supplying Parameters to the Mapping.

 

Next, the mapping includes a user-defined function, "FilterDirectory". This function is recursive, that is, it includes a call to itself. Because it is connected to the recursive element directory, this function will be called as many times as there are nested directory elements in the source XML instance. To support recursive calls, this function was created as regular, not inline (the Inlined use option is not selected in the function's properties). To view the function's properties, right-click an empty area in the mapping and select Function Settings from the context menu, see also Editing User-Defined Functions.

mf_udf_24

As illustrated above, the function takes two parameters as input:

 

1. A complex parameter, Directory, which defines the XML structure to be searched (this parameter is the "haystack").

2. A string parameter, SearchFor, which specifies the file extension to search for (this parameter is the "needle").

 

Double-click the title bar of any of the input or output parameters on the mapping to view their settings.

 

The function also includes a filter component to which the MapForce built-in function contains is connected. The contains function returns true only when the search value matches the "name" attribute (the file name) in the source structure. A true value instructs the filter to copy the current item to the output; otherwise, it is skipped. For more information about filters, see Filters and Conditions.

 

The source and target files of the mapping, as well as the function's directory parameter (both input and output), have all the same schema, Directory.xsd. Since MapForce detected all these types to be assignment compatible, the connection type between the input parameters and the function is "Copy-All", see Copy-All Connections.

 

Running the mapping

To preview the mapping execution in MapForce, click the Output tab. The mapping runs with the default input parameter (".xml") and consequently retrieves only results that match this search criterion. To supply a different search criterion, change the constant connected to the input parameter from ".xml" to ".sps", for example, and run the mapping again.


© 2019 Altova GmbH