<commit_before>#ifndef ARABICA_XSLT_OUTPUT_HANDLER_HPP
#define ARABICA_XSLT_OUTPUT_HANDLER_HPP

#include "xslt_value_validation.hpp"

namespace Arabica
{
namespace XSLT
{

class OutputHandler : public SAX::DefaultHandler<std::string>
{
public:
  OutputHandler(CompilationContext& context) :
    context_(context)
  {
  } // OutputHandler

  virtual void startElement(const std::string& namespaceURI,
                            const std::string& localName,
                            const std::string& qName,
                            const SAX::Attributes<std::string>& atts)
  {
    if(settings_.empty())
    {
      static const char* AllowedMethods[] = { "xml", "html", "text", 0 };
      static const ValueRule rules[] = { { "method", false, "xml", AllowedMethods },
                                         { "version", false, "1.0" },
                                         { "encoding", false, "UTF-8" },
                                         { "omit-xml-declaration", false, No, AllowedYesNo },
                                         { "standalone", false, "", AllowedYesNo },
                                         { "doctype-public", false, ""},
                                         { "doctype-system", false, ""},
                                         { "cdata-section-elements", false, ""},
                                         { "indent", false, No, AllowedYesNo },
                                         { "media-type", false, "" },
                                         { 0, false, 0 } };
      settings_ = gatherAttributes(qName, atts, rules);
      cdataElements_ = extractCDATAElements(settings_["cdata-section-elements"]);

      return;
    } // if(settings_ == 0)

    throw SAX::SAXException(qName + " can not contain elements");
  } // startElement

  virtual void endElement(const std::string& namespaceURI,
                          const std::string& localName,
                          const std::string& qName)
  {
    context_.stylesheet().output_settings(settings_, cdataElements_);
    context_.pop();
  } // endElement

  virtual void characters(const std::string& ch)
  {
    for(std::string::const_iterator i = ch.begin(), e = ch.end(); i != e; ++i)
      if(!Arabica::XML::is_space(*i))
        throw SAX::SAXException("xsl:output element must be empty");
  } // characters
 
private:
  Output::CDATAElements extractCDATAElements(const std::string& cdata_section_elements) const
  {
    Output::CDATAElements elements;

    if(cdata_section_elements.empty())
      return elements;

    std::istringstream is(cdata_section_elements);
    while(!is.eof())
    {
      std::string e;
      is >> e;

      XML::QualifiedName<std::string> qualifiedName = context_.processElementQName(e);
      elements.insert(QName::create(qualifiedName));
    } // while
<commit_msg>normalize whitespace when extracting CDATA element names<commit_after>#ifndef ARABICA_XSLT_OUTPUT_HANDLER_HPP
#define ARABICA_XSLT_OUTPUT_HANDLER_HPP

#include "xslt_value_validation.hpp"

namespace Arabica
{
namespace XSLT
{

class OutputHandler : public SAX::DefaultHandler<std::string>
{
public:
  OutputHandler(CompilationContext& context) :
    context_(context)
  {
  } // OutputHandler

  virtual void startElement(const std::string& namespaceURI,
                            const std::string& localName,
                            const std::string& qName,
                            const SAX::Attributes<std::string>& atts)
  {
    if(settings_.empty())
    {
      static const char* AllowedMethods[] = { "xml", "html", "text", 0 };
      static const ValueRule rules[] = { { "method", false, "xml", AllowedMethods },
                                         { "version", false, "1.0" },
                                         { "encoding", false, "UTF-8" },
                                         { "omit-xml-declaration", false, No, AllowedYesNo },
                                         { "standalone", false, "", AllowedYesNo },
                                         { "doctype-public", false, ""},
                                         { "doctype-system", false, ""},
                                         { "cdata-section-elements", false, ""},
                                         { "indent", false, No, AllowedYesNo },
                                         { "media-type", false, "" },
                                         { 0, false, 0 } };
      settings_ = gatherAttributes(qName, atts, rules);
      cdataElements_ = extractCDATAElements(settings_["cdata-section-elements"]);

      return;
    } // if(settings_ == 0)

    throw SAX::SAXException(qName + " can not contain elements");
  } // startElement

  virtual void endElement(const std::string& namespaceURI,
                          const std::string& localName,
                          const std::string& qName)
  {
    context_.stylesheet().output_settings(settings_, cdataElements_);
    context_.pop();
  } // endElement

  virtual void characters(const std::string& ch)
  {
    for(std::string::const_iterator i = ch.begin(), e = ch.end(); i != e; ++i)
      if(!Arabica::XML::is_space(*i))
        throw SAX::SAXException("xsl:output element must be empty");
  } // characters
 
private:
  Output::CDATAElements extractCDATAElements(const std::string& cdata_section_elements) const
  {
    Output::CDATAElements elements;

    if(cdata_section_elements.empty())
      return elements;

    std::istringstream is(text::normalize_whitespace<std::string, Arabica::default_string_adaptor<std::string> >(cdata_section_elements));
    while(!is.eof())
    {
      std::string e;
      is >> e;

      XML::QualifiedName<std::string> qualifiedName = context_.processElementQName(e);
      elements.insert(QName::create(qualifiedName));
    } // while

{'fraction_non_alphanumeric': 0.12441760138050043, 'fraction_numerical': 0.0024158757549611735, 'mean_word_length': 1.979948586118252, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 40, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6640224', 'n_tokens_mistral': 1567, 'n_tokens_neox': 1508, 'n_words': 314}