Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  txStylesheet.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "txStylesheet.h"

#include <utility>

#include "mozilla/FloatingPoint.h"
#include "txExpr.h"
#include "txInstructions.h"
#include "txKey.h"
#include "txLog.h"
#include "txToplevelItems.h"
#include "txXPathTreeWalker.h"
#include "txXSLTFunctions.h"
#include "txXSLTPatterns.h"

using mozilla::LogLevel;
using mozilla::MakeUnique;
using mozilla::UniquePtr;
using mozilla::Unused;
using mozilla::WrapUnique;

txStylesheet::txStylesheet() : mRootFrame(nullptr) {}

nsresult txStylesheet::init() {
  mRootFrame = new ImportFrame;

  // Create default templates
  // element/root template
  mContainerTemplate = MakeUnique<txPushParams>();

  UniquePtr<txNodeTest> nt(new txNodeTypeTest(txNodeTypeTest::NODE_TYPE));
  UniquePtr<Expr> nodeExpr(
      new LocationStep(nt.get(), LocationStep::CHILD_AXIS));
  Unused << nt.release();

  txPushNewContext* pushContext = new txPushNewContext(std::move(nodeExpr));
  mContainerTemplate->mNext = WrapUnique(pushContext);

  txApplyDefaultElementTemplate* applyTemplates =
      new txApplyDefaultElementTemplate;
  pushContext->mNext = WrapUnique(applyTemplates);

  txLoopNodeSet* loopNodeSet = new txLoopNodeSet(applyTemplates);
  applyTemplates->mNext = WrapUnique(loopNodeSet);

  txPopParams* popParams = new txPopParams;
  loopNodeSet->mNext = WrapUnique(popParams);
  pushContext->mBailTarget = loopNodeSet->mNext.get();

  popParams->mNext = MakeUnique<txReturn>();

  // attribute/textnode template
  nt = MakeUnique<txNodeTypeTest>(txNodeTypeTest::NODE_TYPE);
  nodeExpr = MakeUnique<LocationStep>(nt.get(), LocationStep::SELF_AXIS);
  Unused << nt.release();

  mCharactersTemplate = MakeUnique<txValueOf>(std::move(nodeExpr), false);
  mCharactersTemplate->mNext = MakeUnique<txReturn>();

  // pi/comment/namespace template
  mEmptyTemplate = MakeUnique<txReturn>();

  return NS_OK;
}

txStylesheet::~txStylesheet() {
  // Delete all ImportFrames
  delete mRootFrame;
  txListIterator frameIter(&mImportFrames);
  while (frameIter.hasNext()) {
    delete static_cast<ImportFrame*>(frameIter.next());
  }

  txListIterator instrIter(&mTemplateInstructions);
  while (instrIter.hasNext()) {
    delete static_cast<txInstruction*>(instrIter.next());
  }

  // We can't make the map own its values because then we wouldn't be able
  // to merge attributesets of the same name
  txExpandedNameMap<txInstruction>::iterator attrSetIter(mAttributeSets);
  while (attrSetIter.next()) {
    delete attrSetIter.value();
  }
}

nsresult txStylesheet::findTemplate(const txXPathNode& aNode,
                                    const txExpandedName& aMode,
                                    txIMatchContext* aContext,
                                    ImportFrame* aImportedBy,
                                    txInstruction** aTemplate,
                                    ImportFrame** aImportFrame) {
  NS_ASSERTION(aImportFrame, "missing ImportFrame pointer");

  *aTemplate = nullptr;
  *aImportFrame = nullptr;
  ImportFrame* endFrame = nullptr;
  txListIterator frameIter(&mImportFrames);

  if (aImportedBy) {
    ImportFrame* curr = static_cast<ImportFrame*>(frameIter.next());
    while (curr != aImportedBy) {
      curr = static_cast<ImportFrame*>(frameIter.next());
    }
    endFrame = aImportedBy->mFirstNotImported;
  }

#if defined(TX_TO_STRING)
  txPattern* match = 0;
#endif

  ImportFrame* frame;
  while (!*aTemplate && (frame = static_cast<ImportFrame*>(frameIter.next())) &&
         frame != endFrame) {
    // get templatelist for this mode
    nsTArray<MatchableTemplate>* templates =
        frame->mMatchableTemplates.get(aMode);

    if (templates) {
      // Find template with highest priority
      uint32_t i, len = templates->Length();
      for (i = 0; i < len && !*aTemplate; ++i) {
        MatchableTemplate& templ = (*templates)[i];
        bool matched;
        nsresult rv = templ.mMatch->matches(aNode, aContext, matched);
        NS_ENSURE_SUCCESS(rv, rv);

        if (matched) {
          *aTemplate = templ.mFirstInstruction;
          *aImportFrame = frame;
#if defined(TX_TO_STRING)
          match = templ.mMatch.get();
#endif
        }
      }
    }
  }

  if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Debug)) {
    nsAutoString mode, nodeName;
    if (aMode.mLocalName) {
      aMode.mLocalName->ToString(mode);
    }
    txXPathNodeUtils::getNodeName(aNode, nodeName);
    if (*aTemplate) {
      nsAutoString matchAttr;
#ifdef TX_TO_STRING
      match->toString(matchAttr);
#endif
      MOZ_LOG(txLog::xslt, LogLevel::Debug,
              ("MatchTemplate, Pattern %s, Mode %s, Node %s\n",
               NS_LossyConvertUTF16toASCII(matchAttr).get(),
               NS_LossyConvertUTF16toASCII(mode).get(),
               NS_LossyConvertUTF16toASCII(nodeName).get()));
    } else {
      MOZ_LOG(txLog::xslt, LogLevel::Debug,
              ("No match, Node %s, Mode %s\n",
               NS_LossyConvertUTF16toASCII(nodeName).get(),
               NS_LossyConvertUTF16toASCII(mode).get()));
    }
  }

  if (!*aTemplate) {
    // Test for these first since a node can be both a text node
    // and a root (if it is orphaned)
    if (txXPathNodeUtils::isAttribute(aNode) ||
        txXPathNodeUtils::isText(aNode)) {
      *aTemplate = mCharactersTemplate.get();
    } else if (txXPathNodeUtils::isElement(aNode) ||
               txXPathNodeUtils::isRoot(aNode)) {
      *aTemplate = mContainerTemplate.get();
    } else {
      *aTemplate = mEmptyTemplate.get();
    }
  }

  return NS_OK;
}

txDecimalFormat* txStylesheet::getDecimalFormat(const txExpandedName& aName) {
  return mDecimalFormats.get(aName);
}

txInstruction* txStylesheet::getAttributeSet(const txExpandedName& aName) {
  return mAttributeSets.get(aName);
}

txInstruction* txStylesheet::getNamedTemplate(const txExpandedName& aName) {
  return mNamedTemplates.get(aName);
}

txOutputFormat* txStylesheet::getOutputFormat() { return &mOutputFormat; }

txStylesheet::GlobalVariable* txStylesheet::getGlobalVariable(
    const txExpandedName& aName) {
  return mGlobalVariables.get(aName);
}

const txOwningExpandedNameMap<txXSLKey>& txStylesheet::getKeyMap() {
  return mKeys;
}

nsresult txStylesheet::isStripSpaceAllowed(const txXPathNode& aNode,
                                           txIMatchContext* aContext,
                                           bool& aAllowed) {
  int32_t frameCount = mStripSpaceTests.Length();
  if (frameCount == 0) {
    aAllowed = false;

    return NS_OK;
  }

  txXPathTreeWalker walker(aNode);

  if (txXPathNodeUtils::isText(walker.getCurrentPosition()) &&
      (!txXPathNodeUtils::isWhitespace(aNode) || !walker.moveToParent())) {
    aAllowed = false;

    return NS_OK;
  }

  const txXPathNode& node = walker.getCurrentPosition();

  if (!txXPathNodeUtils::isElement(node)) {
    aAllowed = false;

    return NS_OK;
  }

  // check Whitespace stipping handling list against given Node
  int32_t i;
  for (i = 0; i < frameCount; ++i) {
    const auto& sst = mStripSpaceTests[i];
    bool matched;
    nsresult rv = sst->matches(node, aContext, matched);
    NS_ENSURE_SUCCESS(rv, rv);

    if (matched) {
      aAllowed = sst->stripsSpace() && !XMLUtils::getXMLSpacePreserve(node);

      return NS_OK;
    }
  }

  aAllowed = false;

  return NS_OK;
}

nsresult txStylesheet::doneCompiling() {
  nsresult rv = NS_OK;
  // Collect all importframes into a single ordered list
  txListIterator frameIter(&mImportFrames);
  frameIter.addAfter(mRootFrame);

  mRootFrame = nullptr;
  frameIter.next();
  rv = addFrames(frameIter);
  NS_ENSURE_SUCCESS(rv, rv);

  // Loop through importframes in decreasing-precedence-order and process
  // all items
  frameIter.reset();
  ImportFrame* frame;
  while ((frame = static_cast<ImportFrame*>(frameIter.next()))) {
    nsTArray<txStripSpaceTest*> frameStripSpaceTests;

    txListIterator itemIter(&frame->mToplevelItems);
    itemIter.resetToEnd();
    txToplevelItem* item;
    while ((item = static_cast<txToplevelItem*>(itemIter.previous()))) {
      switch (item->getType()) {
        case txToplevelItem::attributeSet: {
          rv = addAttributeSet(static_cast<txAttributeSetItem*>(item));
          NS_ENSURE_SUCCESS(rv, rv);
          break;
        }
        case txToplevelItem::dummy:
        case txToplevelItem::import: {
          break;
        }
        case txToplevelItem::output: {
          mOutputFormat.merge(static_cast<txOutputItem*>(item)->mFormat);
          break;
        }
        case txToplevelItem::stripSpace: {
          rv = addStripSpace(static_cast<txStripSpaceItem*>(item),
                             frameStripSpaceTests);
          NS_ENSURE_SUCCESS(rv, rv);
          break;
        }
        case txToplevelItem::templ: {
          rv = addTemplate(static_cast<txTemplateItem*>(item), frame);
          NS_ENSURE_SUCCESS(rv, rv);

          break;
        }
        case txToplevelItem::variable: {
          rv = addGlobalVariable(static_cast<txVariableItem*>(item));
          NS_ENSURE_SUCCESS(rv, rv);

          break;
        }
      }
      delete item;
      itemIter.remove();  // remove() moves to the previous
      itemIter.next();
    }
    mStripSpaceTests.AppendElements(frameStripSpaceTests);
    frameStripSpaceTests.Clear();
  }

  if (!mDecimalFormats.get(txExpandedName())) {
    UniquePtr<txDecimalFormat> format(new txDecimalFormat);
    rv = mDecimalFormats.add(txExpandedName(), format.get());
    NS_ENSURE_SUCCESS(rv, rv);

    Unused << format.release();
  }

  return NS_OK;
}

nsresult txStylesheet::addTemplate(txTemplateItem* aTemplate,
                                   ImportFrame* aImportFrame) {
  NS_ASSERTION(aTemplate, "missing template");

  txInstruction* instr = aTemplate->mFirstInstruction.get();
  mTemplateInstructions.add(instr);

  // mTemplateInstructions now owns the instructions
  Unused << aTemplate->mFirstInstruction.release();

  if (!aTemplate->mName.isNull()) {
    nsresult rv = mNamedTemplates.add(aTemplate->mName, instr);
    NS_ENSURE_TRUE(NS_SUCCEEDED(rv) || rv == NS_ERROR_XSLT_ALREADY_SET, rv);
  }

  if (!aTemplate->mMatch) {
    // This is no error, see section 6 Named Templates

    return NS_OK;
  }

  // get the txList for the right mode
  nsTArray<MatchableTemplate>* templates =
      aImportFrame->mMatchableTemplates.get(aTemplate->mMode);

  if (!templates) {
    UniquePtr<nsTArray<MatchableTemplate>> newList(
        new nsTArray<MatchableTemplate>);
    nsresult rv =
        aImportFrame->mMatchableTemplates.set(aTemplate->mMode, newList.get());
    NS_ENSURE_SUCCESS(rv, rv);

    templates = newList.release();
  }

  // Add the simple patterns to the list of matchable templates, according
  // to default priority
  UniquePtr<txPattern> simple = std::move(aTemplate->mMatch);
  UniquePtr<txPattern> unionPattern;
  if (simple->getType() == txPattern::UNION_PATTERN) {
    unionPattern = std::move(simple);
    simple = WrapUnique(unionPattern->getSubPatternAt(0));
    unionPattern->setSubPatternAt(0, nullptr);
  }

  uint32_t unionPos = 1;  // only used when unionPattern is set
  while (simple) {
    double priority = aTemplate->mPrio;
    if (std::isnan(priority)) {
      priority = simple->getDefaultPriority();
      NS_ASSERTION(!std::isnan(priority),
                   "simple pattern without default priority");
    }

    uint32_t i, len = templates->Length();
    for (i = 0; i < len; ++i) {
      if (priority > (*templates)[i].mPriority) {
        break;
      }
    }

    MatchableTemplate* nt = templates->InsertElementAt(i);
    nt->mFirstInstruction = instr;
    nt->mMatch = std::move(simple);
    nt->mPriority = priority;

    if (unionPattern) {
      simple = WrapUnique(unionPattern->getSubPatternAt(unionPos));
      if (simple) {
        unionPattern->setSubPatternAt(unionPos, nullptr);
      }
      ++unionPos;
    }
  }

  return NS_OK;
}

nsresult txStylesheet::addFrames(txListIterator& aInsertIter) {
  ImportFrame* frame = static_cast<ImportFrame*>(aInsertIter.current());
  nsresult rv = NS_OK;
  txListIterator iter(&frame->mToplevelItems);
  txToplevelItem* item;
  while ((item = static_cast<txToplevelItem*>(iter.next()))) {
    if (item->getType() == txToplevelItem::import) {
      txImportItem* import = static_cast<txImportItem*>(item);
      import->mFrame->mFirstNotImported =
          static_cast<ImportFrame*>(aInsertIter.next());
      aInsertIter.addBefore(import->mFrame.release());
      aInsertIter.previous();
      rv = addFrames(aInsertIter);
      NS_ENSURE_SUCCESS(rv, rv);
      aInsertIter.previous();
    }
  }

  return NS_OK;
}

nsresult txStylesheet::addStripSpace(
    txStripSpaceItem* aStripSpaceItem,
    nsTArray<txStripSpaceTest*>& aFrameStripSpaceTests) {
  int32_t testCount = aStripSpaceItem->mStripSpaceTests.Length();
  for (; testCount > 0; --testCount) {
    txStripSpaceTest* sst = aStripSpaceItem->mStripSpaceTests[testCount - 1];
    double priority = sst->getDefaultPriority();
    int32_t i, frameCount = aFrameStripSpaceTests.Length();
    for (i = 0; i < frameCount; ++i) {
      if (aFrameStripSpaceTests[i]->getDefaultPriority() < priority) {
        break;
      }
    }
    aFrameStripSpaceTests.InsertElementAt(i, sst);
    aStripSpaceItem->mStripSpaceTests.RemoveElementAt(testCount - 1);
  }

  return NS_OK;
}

nsresult txStylesheet::addAttributeSet(txAttributeSetItem* aAttributeSetItem) {
  nsresult rv = NS_OK;
  txInstruction* oldInstr = mAttributeSets.get(aAttributeSetItem->mName);
  if (!oldInstr) {
    rv = mAttributeSets.add(aAttributeSetItem->mName,
                            aAttributeSetItem->mFirstInstruction.get());
    NS_ENSURE_SUCCESS(rv, rv);

    Unused << aAttributeSetItem->mFirstInstruction.release();

    return NS_OK;
  }

  // We need to prepend the new instructions before the existing ones.
  txInstruction* instr = aAttributeSetItem->mFirstInstruction.get();
  txInstruction* lastNonReturn = nullptr;
  while (instr->mNext) {
    lastNonReturn = instr;
    instr = instr->mNext.get();
  }

  if (!lastNonReturn) {
    // The new attributeset is empty, so lets just ignore it.
    return NS_OK;
  }

  rv = mAttributeSets.set(aAttributeSetItem->mName,
                          aAttributeSetItem->mFirstInstruction.get());
  NS_ENSURE_SUCCESS(rv, rv);

  Unused << aAttributeSetItem->mFirstInstruction.release();

  lastNonReturn->mNext =
      WrapUnique(oldInstr);  // ...and link up the old instructions.

  return NS_OK;
}

nsresult txStylesheet::addGlobalVariable(txVariableItem* aVariable) {
  if (mGlobalVariables.get(aVariable->mName)) {
    return NS_OK;
  }
  UniquePtr<GlobalVariable> var(new GlobalVariable(
      std::move(aVariable->mValue), std::move(aVariable->mFirstInstruction),
      aVariable->mIsParam));
  nsresult rv = mGlobalVariables.add(aVariable->mName, var.get());
  NS_ENSURE_SUCCESS(rv, rv);

  Unused << var.release();

  return NS_OK;
}

nsresult txStylesheet::addKey(const txExpandedName& aName,
                              UniquePtr<txPattern> aMatch,
                              UniquePtr<Expr> aUse) {
  nsresult rv = NS_OK;

  txXSLKey* xslKey = mKeys.get(aName);
  if (!xslKey) {
    xslKey = new txXSLKey(aName);
    rv = mKeys.add(aName, xslKey);
    if (NS_FAILED(rv)) {
      delete xslKey;
      return rv;
    }
  }
  if (!xslKey->addKey(std::move(aMatch), std::move(aUse))) {
    return NS_ERROR_OUT_OF_MEMORY;
  }
  return NS_OK;
}

nsresult txStylesheet::addDecimalFormat(const txExpandedName& aName,
                                        UniquePtr<txDecimalFormat>&& aFormat) {
  txDecimalFormat* existing = mDecimalFormats.get(aName);
  if (existing) {
    NS_ENSURE_TRUE(existing->isEqual(aFormat.get()),
                   NS_ERROR_XSLT_PARSE_FAILURE);

    return NS_OK;
  }

  nsresult rv = mDecimalFormats.add(aName, aFormat.get());
  NS_ENSURE_SUCCESS(rv, rv);

  Unused << aFormat.release();

  return NS_OK;
}

txStylesheet::ImportFrame::~ImportFrame() {
  txListIterator tlIter(&mToplevelItems);
  while (tlIter.hasNext()) {
    delete static_cast<txToplevelItem*>(tlIter.next());
  }
}

txStylesheet::GlobalVariable::GlobalVariable(UniquePtr<Expr>&& aExpr,
                                             UniquePtr<txInstruction>&& aInstr,
                                             bool aIsParam)
    : mExpr(std::move(aExpr)),
      mFirstInstruction(std::move(aInstr)),
      mIsParam(aIsParam) {}

Messung V0.5
C=94 H=92 G=92

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge