New files for bug 151002 (abstract the content by a treewalker). Patch by me, with parts by Pike and sicking. r=sicking, sr=jst.

This commit is contained in:
peter%propagandism.org 2003-11-18 22:50:42 +00:00
parent e166d5028a
commit 7a81f51c35
4 changed files with 1806 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,419 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Peter Van der Beken <peterv@netscape.com>
* Axel Hecht <axel@pike.org>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "txXPathTreeWalker.h"
#include "nsPrintfCString.h"
#include "nsReadableUtils.h"
#include "nsString.h"
#include "XMLUtils.h"
txXPathTreeWalker::txXPathTreeWalker(const txXPathTreeWalker& aOther)
: mPosition(aOther.mPosition)
{
}
txXPathTreeWalker::txXPathTreeWalker(const txXPathNode& aNode)
: mPosition(aNode)
{
}
txXPathTreeWalker::~txXPathTreeWalker()
{
}
#define INNER mPosition.mInner
PRBool
txXPathTreeWalker::moveToElementById(const nsAString& aID)
{
Document* document;
if (INNER->nodeType == Node::DOCUMENT_NODE) {
document = NS_STATIC_CAST(Document*, INNER);
}
else {
document = INNER->ownerDocument;
}
Element* element =
document->getElementById(aID);
if (!element) {
return PR_FALSE;
}
INNER = element;
return PR_TRUE;
}
PRBool
txXPathTreeWalker::moveToFirstAttribute()
{
if (INNER->nodeType != Node::ELEMENT_NODE) {
return PR_FALSE;
}
Element* element = NS_STATIC_CAST(Element*, INNER);
NamedNodeMap* attrs = element->getAttributes();
NodeListDefinition::ListItem* item = attrs->firstItem;
// skip XMLNS attributes
while (item && item->node->getNamespaceID() == kNameSpaceID_XMLNS) {
item = item->next;
}
if (!item) {
return PR_FALSE;
}
INNER = NS_STATIC_CAST(NodeDefinition*, item->node);
return PR_TRUE;
}
PRBool
txXPathTreeWalker::moveToNextAttribute()
{
// XXX an assertion should be enough here with the current code
if (INNER->nodeType != Node::ATTRIBUTE_NODE) {
return PR_FALSE;
}
Node* element = INNER->getXPathParent();
NamedNodeMap* attrs = element->getAttributes();
// find the ListItem for the current Attr
NodeListDefinition::ListItem* item = attrs->firstItem;
while (item->node != INNER) {
item = item->next;
}
NS_ASSERTION(item, "Attr not attribute of it's owner?");
// next item
item = item->next;
// skip XMLNS attributes
while (item && item->node->getNamespaceID() == kNameSpaceID_XMLNS) {
item = item->next;
}
if (!item) {
return PR_FALSE;
}
INNER = NS_STATIC_CAST(NodeDefinition*, item->node);
return PR_TRUE;
}
PRBool
txXPathTreeWalker::moveToFirstChild()
{
if (!INNER->firstChild) {
return PR_FALSE;
}
INNER = INNER->firstChild;
return PR_TRUE;
}
PRBool
txXPathTreeWalker::moveToLastChild()
{
if (!INNER->lastChild) {
return PR_FALSE;
}
INNER = INNER->lastChild;
return PR_TRUE;
}
PRBool
txXPathTreeWalker::moveToNextSibling()
{
if (!INNER->nextSibling) {
return PR_FALSE;
}
INNER = INNER->nextSibling;
return PR_TRUE;
}
PRBool
txXPathTreeWalker::moveToPreviousSibling()
{
if (!INNER->previousSibling) {
return PR_FALSE;
}
INNER = INNER->previousSibling;
return PR_TRUE;
}
PRBool
txXPathTreeWalker::moveToParent()
{
if (INNER->nodeType == Node::ATTRIBUTE_NODE) {
INNER = NS_STATIC_CAST(NodeDefinition*, INNER->getXPathParent());
return PR_TRUE;
}
if (INNER->nodeType == Node::DOCUMENT_NODE) {
return PR_FALSE;
}
NS_ASSERTION(INNER->parentNode, "orphaned node shouldn't happen");
INNER = INNER->parentNode;
return PR_TRUE;
}
txXPathNode::txXPathNode(const txXPathNode& aNode)
: mInner(aNode.mInner)
{
}
PRBool
txXPathNode::operator==(const txXPathNode& aNode) const
{
return (mInner == aNode.mInner);
}
/* static */
PRBool
txXPathNodeUtils::getAttr(const txXPathNode& aNode, nsIAtom* aLocalName,
PRInt32 aNSID, nsAString& aValue)
{
if (aNode.mInner->getNodeType() != Node::ELEMENT_NODE) {
return PR_FALSE;
}
Element* elem = NS_STATIC_CAST(Element*, aNode.mInner);
return elem->getAttr(aLocalName, aNSID, aValue);
}
/* static */
already_AddRefed<nsIAtom>
txXPathNodeUtils::getLocalName(const txXPathNode& aNode)
{
nsIAtom* localName;
return aNode.mInner->getLocalName(&localName) ? localName : nsnull;
}
/* static */
void
txXPathNodeUtils::getLocalName(const txXPathNode& aNode, nsAString& aLocalName)
{
nsCOMPtr<nsIAtom> localName;
PRBool hasName = aNode.mInner->getLocalName(getter_AddRefs(localName));
if (hasName && localName) {
localName->ToString(aLocalName);
}
}
/* static */
void
txXPathNodeUtils::getNodeName(const txXPathNode& aNode, nsAString& aName)
{
aNode.mInner->getNodeName(aName);
}
/* static */
PRInt32
txXPathNodeUtils::getNamespaceID(const txXPathNode& aNode)
{
return aNode.mInner->getNamespaceID();
}
/* static */
void
txXPathNodeUtils::getNamespaceURI(const txXPathNode& aNode, nsAString& aURI)
{
aNode.mInner->getNamespaceURI(aURI);
}
/* static */
PRUint16
txXPathNodeUtils::getNodeType(const txXPathNode& aNode)
{
return aNode.mInner->getNodeType();
}
/* static */
void
txXPathNodeUtils::appendNodeValueHelper(NodeDefinition* aNode,
nsAString& aResult)
{
NodeDefinition* child = NS_STATIC_CAST(NodeDefinition*,
aNode->getFirstChild());
while (child) {
switch (child->getNodeType()) {
case Node::TEXT_NODE:
{
aResult.Append(child->nodeValue);
}
case Node::ELEMENT_NODE:
{
appendNodeValueHelper(child, aResult);
}
}
child = NS_STATIC_CAST(NodeDefinition*, child->getNextSibling());
}
}
/* static */
void
txXPathNodeUtils::appendNodeValue(const txXPathNode& aNode, nsAString& aResult)
{
unsigned short type = aNode.mInner->getNodeType();
if (type == Node::ATTRIBUTE_NODE ||
type == Node::COMMENT_NODE ||
type == Node::PROCESSING_INSTRUCTION_NODE ||
type == Node::TEXT_NODE) {
aResult.Append(aNode.mInner->nodeValue);
return;
}
NS_ASSERTION(type == Node::ELEMENT_NODE || type == Node::DOCUMENT_NODE,
"Element or Document expected");
appendNodeValueHelper(aNode.mInner, aResult);
}
/* static */
PRBool
txXPathNodeUtils::isWhitespace(const txXPathNode& aNode)
{
NS_ASSERTION(aNode.mInner->nodeType == Node::TEXT_NODE, "Wrong type!");
return XMLUtils::isWhitespace(aNode.mInner->nodeValue);
}
/* static */
txXPathNode*
txXPathNodeUtils::getDocument(const txXPathNode& aNode)
{
if (aNode.mInner->nodeType == Node::DOCUMENT_NODE) {
return new txXPathNode(aNode);
}
return new txXPathNode(aNode.mInner->ownerDocument);
}
/* static */
txXPathNode*
txXPathNodeUtils::getOwnerDocument(const txXPathNode& aNode)
{
return getDocument(aNode);
}
#ifndef HAVE_64BIT_OS
#define kFmtSize 13
const char gPrintfFmt[] = "id0x%08p";
#else
#define kFmtSize 21
const char gPrintfFmt[] = "id0x%016p";
#endif
/* static */
nsresult
txXPathNodeUtils::getXSLTId(const txXPathNode& aNode,
nsAString& aResult)
{
CopyASCIItoUCS2(nsPrintfCString(kFmtSize, gPrintfFmt, aNode.mInner),
aResult);
return NS_OK;
}
/* static */
void
txXPathNodeUtils::getBaseURI(const txXPathNode& aNode, nsAString& aURI)
{
aNode.mInner->getBaseURI(aURI);
}
/* static */
PRIntn
txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
const txXPathNode& aOtherNode)
{
// First check for equal nodes.
if (aNode == aOtherNode) {
return 0;
}
return aNode.mInner->compareDocumentPosition(aOtherNode.mInner);
}
/* static */
txXPathNode*
txXPathNativeNode::createXPathNode(Node* aNode)
{
if (aNode != nsnull) {
return new txXPathNode(NS_STATIC_CAST(NodeDefinition*, aNode));
}
return nsnull;
}
/* static */
nsresult
txXPathNativeNode::getElement(const txXPathNode& aNode, Element** aResult)
{
if (aNode.mInner->getNodeType() != Node::ELEMENT_NODE) {
return NS_ERROR_FAILURE;
}
*aResult = NS_STATIC_CAST(Element*, aNode.mInner);
return NS_OK;
}
/* static */
nsresult
txXPathNativeNode::getDocument(const txXPathNode& aNode, Document** aResult)
{
if (aNode.mInner->getNodeType() != Node::DOCUMENT_NODE) {
return NS_ERROR_FAILURE;
}
*aResult = NS_STATIC_CAST(Document*, aNode.mInner);
return NS_OK;
}

View File

@ -0,0 +1,121 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Peter Van der Beken <peterv@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef txXPathNode_h__
#define txXPathNode_h__
#ifdef TX_EXE
#include "dom.h"
#else
#include "nsAutoPtr.h"
#include "nsIContent.h"
#include "nsIDocument.h"
#include "nsIDOMNode.h"
#include "nsINameSpaceManager.h"
extern nsINameSpaceManager* gTxNameSpaceManager;
#endif
#ifdef TX_EXE
typedef Node txXPathNodeType;
#else
typedef nsIDOMNode txXPathNodeType;
#endif
class txXPathNode
{
public:
PRBool operator==(const txXPathNode& aNode) const;
PRBool operator!=(const txXPathNode& aNode) const
{
return !(*this == aNode);
}
private:
friend class txNodeSet;
friend class txXPathNativeNode;
friend class txXPathNodeUtils;
friend class txXPathTreeWalker;
#ifdef TX_EXE
txXPathNode(NodeDefinition* aNode) : mInner(aNode)
{
}
txXPathNode(const txXPathNode& aNode);
NodeDefinition* mInner;
#else
txXPathNode(nsIDocument* aDocument) : mDocument(aDocument),
mIndex(eDocument)
{
}
txXPathNode(nsIContent* aContent, PRUint32 aIndex = eContent)
: mContent(aContent),
mIndex(aIndex)
{
}
txXPathNode(const txXPathNode& aNode);
PRBool isDocument() const
{
return mIndex == eDocument;
};
PRBool isContent() const
{
return mIndex == eContent;
};
PRBool isAttribute() const
{
return mIndex != eDocument && mIndex != eContent;
};
enum PositionType
{
eDocument = (PRUint32)-2,
eContent = (PRUint32)-1
};
union {
nsIDocument* mDocument; // eDocument
nsIContent* mContent; // eContent, eAttribute
};
PRUint32 mIndex;
#endif
};
#endif /* txXPathNode_h__ */

View File

@ -0,0 +1,245 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Peter Van der Beken <peterv@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef txXPathTreeWalker_h__
#define txXPathTreeWalker_h__
#include "baseutils.h"
#include "TxObject.h"
#include "txXPathNode.h"
class nsAString;
class nsIAtom;
#ifndef TX_EXE
#include "nsVoidArray.h"
class txUint32Array : public nsVoidArray
{
public:
PRBool AppendValue(PRUint32 aValue)
{
return InsertElementAt(NS_INT32_TO_PTR(aValue), Count());
}
PRBool RemoveValueAt(PRUint32 aIndex)
{
return RemoveElementsAt(aIndex, 1);
}
PRInt32 ValueAt(PRUint32 aIndex) const
{
return NS_PTR_TO_INT32(ElementAt(aIndex));
}
};
class nsIDOMDocument;
#endif
class txXPathTreeWalker
{
public:
explicit txXPathTreeWalker(const txXPathTreeWalker& aOther);
explicit txXPathTreeWalker(const txXPathNode& aNode);
~txXPathTreeWalker();
PRBool getAttr(nsIAtom* aLocalName, PRInt32 aNSID, nsAString& aValue) const;
PRInt32 getNamespaceID() const;
PRUint16 getNodeType() const;
void appendNodeValue(nsAString& aResult) const;
void getNodeName(nsAString& aName) const;
void moveTo(const txXPathTreeWalker& aWalker);
PRBool moveToParent();
PRBool moveToElementById(const nsAString& aID);
PRBool moveToFirstAttribute();
PRBool moveToNextAttribute();
PRBool moveToFirstChild();
PRBool moveToLastChild();
PRBool moveToNextSibling();
PRBool moveToPreviousSibling();
PRBool isOnNode(const txXPathNode& aNode) const;
const txXPathNode& getCurrentPosition() const;
private:
txXPathNode mPosition;
#ifndef TX_EXE
PRBool moveToValidAttribute(PRUint32 aStartIndex);
PRBool moveToSibling(PRInt32 aDir);
PRUint32 mCurrentIndex;
txUint32Array mDescendants;
#endif
};
class txXPathNodeUtils
{
public:
static PRBool getAttr(const txXPathNode& aNode, nsIAtom* aLocalName,
PRInt32 aNSID, nsAString& aValue);
static already_AddRefed<nsIAtom> getLocalName(const txXPathNode& aNode);
static void getLocalName(const txXPathNode& aNode,
nsAString& aLocalName);
static void getNodeName(const txXPathNode& aNode,
nsAString& aName);
static PRInt32 getNamespaceID(const txXPathNode& aNode);
static void getNamespaceURI(const txXPathNode& aNode, nsAString& aURI);
static PRUint16 getNodeType(const txXPathNode& aNode);
static void appendNodeValue(const txXPathNode& aNode, nsAString& aResult);
static PRBool isWhitespace(const txXPathNode& aNode);
static txXPathNode* getDocument(const txXPathNode& aNode);
static txXPathNode* getOwnerDocument(const txXPathNode& aNode);
static PRInt32 getUniqueIdentifier(const txXPathNode& aNode);
static nsresult getXSLTId(const txXPathNode& aNode, nsAString& aResult);
static void release(txXPathNode* aNode);
static void getBaseURI(const txXPathNode& aNode, nsAString& aURI);
static PRIntn comparePosition(const txXPathNode& aNode,
const txXPathNode& aOtherNode);
#ifdef TX_EXE
private:
static void appendNodeValueHelper(NodeDefinition* aNode, nsAString& aResult);
#endif
};
#ifdef TX_EXE
class txXPathNativeNode
{
public:
static txXPathNode* createXPathNode(Node* aNode);
static nsresult getElement(const txXPathNode& aNode, Element** aResult);
static nsresult getDocument(const txXPathNode& aNode, Document** aResult);
};
#else
class txXPathNativeNode
{
public:
static txXPathNode* createXPathNode(nsIDOMNode* aNode);
static txXPathNode* createXPathNode(nsIDOMDocument* aDocument);
static nsresult getNode(const txXPathNode& aNode, nsIDOMNode** aResult);
static nsIContent* getContent(const txXPathNode& aNode);
static nsIDocument* getDocument(const txXPathNode& aNode);
};
#endif
inline const txXPathNode&
txXPathTreeWalker::getCurrentPosition() const
{
return mPosition;
}
inline PRBool
txXPathTreeWalker::getAttr(nsIAtom* aLocalName, PRInt32 aNSID,
nsAString& aValue) const
{
return txXPathNodeUtils::getAttr(mPosition, aLocalName, aNSID, aValue);
}
inline PRInt32
txXPathTreeWalker::getNamespaceID() const
{
return txXPathNodeUtils::getNamespaceID(mPosition);
}
inline PRUint16
txXPathTreeWalker::getNodeType() const
{
return txXPathNodeUtils::getNodeType(mPosition);
}
inline void
txXPathTreeWalker::appendNodeValue(nsAString& aResult) const
{
txXPathNodeUtils::appendNodeValue(mPosition, aResult);
}
inline void
txXPathTreeWalker::getNodeName(nsAString& aName) const
{
txXPathNodeUtils::getNodeName(mPosition, aName);
}
inline void
txXPathTreeWalker::moveTo(const txXPathTreeWalker& aWalker)
{
#ifdef TX_EXE
mPosition.mInner = aWalker.mPosition.mInner;
#else
mPosition.mIndex = aWalker.mPosition.mIndex;
// Hopefully it's ok to access mContent through mDocument.
mPosition.mDocument = aWalker.mPosition.mDocument;
mCurrentIndex = aWalker.mCurrentIndex;
mDescendants.Clear();
#endif
}
inline PRBool
txXPathTreeWalker::isOnNode(const txXPathNode& aNode) const
{
return (mPosition == aNode);
}
/* static */
inline PRInt32
txXPathNodeUtils::getUniqueIdentifier(const txXPathNode& aNode)
{
#ifdef TX_EXE
return NS_PTR_TO_INT32(aNode.mInner);
#else
NS_PRECONDITION(aNode.mIndex == txXPathNode::eDocument,
"Only implemented for documents.");
return NS_PTR_TO_INT32(aNode.mDocument);
#endif
}
/* static */
inline void
txXPathNodeUtils::release(txXPathNode* aNode)
{
#ifdef TX_EXE
delete aNode->mInner;
#else
NS_RELEASE(aNode->mDocument);
#endif
}
#endif /* txXPathTreeWalker_h__ */