virtual void write()
    {
        StringBuffer rowTag;
        OwnedRoxieString xmlpath(helper->getXmlIteratorPath());
        if (!xmlpath)
        {
            rowTag.append(DEFAULTXMLROWTAG);
        }
        else
        {
            const char *path = xmlpath;
            if (*path == '/') path++;
            if (strchr(path, '/')) UNIMPLEMENTED;
            rowTag.append(path);
        }

        StringBuffer out;
        if (!dlfn.isExternal() || firstNode()) // if external, 1 header,footer
        {
            OwnedRoxieString suppliedHeader(helper->getHeader());
            if (kind==TAKjsonwrite)
                buildJsonHeader(out, suppliedHeader, rowTag);
            else if (suppliedHeader)
                out.set(suppliedHeader);
            else
                out.set(DEFAULTXMLHEADER).newline();
            outraw->write(out.length(), out.str());
            if (calcFileCrc)
                fileCRC.tally(out.length(), out.str());
        }
        Owned<IXmlWriterExt> writer = createIXmlWriterExt(helper->getXmlFlags(), 0, NULL, (kind==TAKjsonwrite) ? WTJSON : WTStandard);
        writer->outputBeginArray(rowTag); //need this to format rows, even if not outputting it below
        while(!abortSoon)
        {
            OwnedConstThorRow row = input->ungroupedNextRow();
            if (!row)
                break;
            writer->clear().outputBeginNested(rowTag, false);
            helper->toXML((const byte *)row.get(), *writer);
            writer->outputEndNested(rowTag);
            outraw->write(writer->length(), writer->str());
            if (calcFileCrc)
                fileCRC.tally(writer->length(), writer->str());
            processed++;
        }
        if (!dlfn.isExternal() || lastNode()) // if external, 1 header,footer
        {
            OwnedRoxieString suppliedFooter(helper->getFooter());
            if (kind==TAKjsonwrite)
                buildJsonFooter(out.clear().newline(), suppliedFooter, rowTag);
            else if (suppliedFooter)
                out.set(suppliedFooter);
            else
                out.set(DEFAULTXMLFOOTER).newline();
            outraw->write(out.length(), out.str());
            if (calcFileCrc)
                fileCRC.tally(out.length(), out.str());
        }
    }
    virtual void write()
    {
        StringBuffer rowTag;
        OwnedRoxieString xmlpath(helper->getXmlIteratorPath());
        if (!xmlpath)
        {
            rowTag.append("Row");
        }
        else
        {
            const char *path = xmlpath;
            if (*path == '/') path++;
            if (strchr(path, '/')) UNIMPLEMENTED;
            rowTag.append(path);
        }

        StringBuffer xmlOutput;
        CommonXmlWriter xmlWriter(helper->getXmlFlags());
        if (!dlfn.isExternal() || firstNode()) // if external, 1 header,footer
        {
            OwnedRoxieString header(helper->getHeader());
            if (header)
                xmlOutput.clear().append(header);
            else
                xmlOutput.clear().append("<Dataset>").newline();
            outraw->write(xmlOutput.length(), xmlOutput.toCharArray());
            if (calcFileCrc)
                fileCRC.tally(xmlOutput.length(), xmlOutput.toCharArray());
        }
        while(!abortSoon)
        {
            OwnedConstThorRow row = input->ungroupedNextRow();
            if (!row)
                break;
            xmlWriter.clear().outputBeginNested(rowTag, false);
            helper->toXML((const byte *)row.get(), xmlWriter);
            xmlWriter.outputEndNested(rowTag);
            outraw->write(xmlWriter.length(), xmlWriter.str());
            if (calcFileCrc)
                fileCRC.tally(xmlWriter.length(), xmlWriter.str());
            processed++;
        }
        if (!dlfn.isExternal() || lastNode()) // if external, 1 header,footer
        {
            OwnedRoxieString footer(helper->getFooter());
            if (footer)
                xmlOutput.clear().append(footer);
            else
                xmlOutput.clear().append("</Dataset>").newline();
            outraw->write(xmlOutput.length(), xmlOutput.toCharArray());
            if (calcFileCrc)
                fileCRC.tally(xmlOutput.length(), xmlOutput.toCharArray());
        }
    }