Feeding the report data from an XML file (Swift)

Report data can come from an XML file.

  1. Import the GRE library.
    // You must import the GRE library and add it to the linker options at build time.
    //        -I "$(GREDIR)/lib/swift" -L "$(GREDIR)/lib/swift" -lgre
    import libgre
  2. Create a class as the delegate of a Swift XML parser.
    // When implementing the Swift XMLParserDelegate protocol, data are send to a content handler of the GRW C API,
    // by calling the startElement(), attribute(), characters() and endElement() functions.
    private class FileRunner: NSObject, XMLParserDelegate {
        var contentHandler: UnsafeMutablePointer<ContentHandler>
    
        init?(_ contentHandler: UnsafeMutablePointer<ContentHandler>) {
            self.contentHandler = contentHandler
        }
    
        func parser(_ parser: XMLParser, didStartElement elementName: String,
                    namespaceURI: String?, qualifiedName qName: String?,
                    attributes attributeDict: [String : String]) {
            // Send a start element to the content handler.
            startElement(contentHandler, elementName)
            // Send attributes to the content handler.
            for (attributeName, attributeValue) in attributeDict {
                attribute(contentHandler, attributeName, attributeValue)
            }
        }
    
        func parser(_ parser: XMLParser, didEndElement elementName: String,
                    namespaceURI: String?, qualifiedName qName: String?) {
            // Send an end element to the content handler.
            endElement(contentHandler, elementName)
        }
    
        func parser(_ parser: XMLParser, foundCharacters string: String) {
            // Send character data to the content handler.
            characters(contentHandler, string)
        }
    }
  3. Create a function that reads and parses the XML file.
    public func runFromXML(_ contentHandler: UnsafeMutablePointer<ContentHandler>, _ fileName: String) {
        // Create an XML parser.
        let fileURL = URL(fileURLWithPath: fileName)
        guard let parser = XMLParser(contentsOf: fileURL) else {
            print("Info: Cannot read data.")
            exit(EXIT_FAILURE)
        }
        // Create the delegate of the XML parser.
        let fileRunner = FileRunner(contentHandler)
        parser.delegate = fileRunner
        // Start the XML parsing.
        parser.parse()
    }
  4. Feed the report data from the XML file.
    var designFile: String = "SalesList.4rp"
    var outputFilename: String = "SalesList.pdf
    
    // Create a runtime configuration.
    let runtimeConfiguration = createRuntimeConfiguration(designFile)
    setOutputFileName(runtimeConfiguration, outputFilename)
    selectDevice (runtimeConfiguration, PDF)
    configureDistributedProcessing(runtimeConfiguration, "127.0.0.1", 7000)
    
    // Create a content handler.
    guard let contentHandler = createContentHandler(runtimeConfiguration) else {
        print("Error: Report Writer server may not be started. Launch it with the following command: greportwriter -l 7000")
        exit(EXIT_FAILURE)
    }
    
    // Run report from XML file.
    runFromXML(contentHandler, "my_data_file.xml")
    
    // Destroy the content handler.
    destroy_content_handler (contentHandler)
    
    exit(EXIT_SUCCESS)

Format of the incoming XML file

The XML file should be organized with Report, Group and OnEveryRow elements. For example:
<Report>
  <Group>
    <Group>
      <Group>
        <OnEveryRow>
          <orderline.orders.orderid>5</orderline.orders.orderid>
          <orderline.orders.userid>bloggs</orderline.orders.userid>
          <orderline.orders.orderdate>2014-06-24</orderline.orders.orderdate>
          ...
          <lineitemprice>122.0</lineitemprice>
          <overalltotal>122.0</overalltotal>
          <usertotal>122.0</usertotal>
          <ordertotal>122.0</ordertotal>
        </OnEveryRow>
      </Group>
      ...