2001-09-25 01:32:19 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
2004-04-17 21:52:36 +00:00
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
2000-09-10 02:17:54 +00:00
|
|
|
*
|
2004-04-17 21:52:36 +00:00
|
|
|
* 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/
|
2000-09-10 02:17:54 +00:00
|
|
|
*
|
2001-09-25 01:32:19 +00:00
|
|
|
* 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.
|
2000-09-10 02:17:54 +00:00
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
2004-04-17 21:52:36 +00:00
|
|
|
* The Initial Developer of the Original Code is
|
2001-09-25 01:32:19 +00:00
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
2000-09-10 02:17:54 +00:00
|
|
|
*
|
2001-09-25 01:32:19 +00:00
|
|
|
* Contributor(s):
|
2008-10-21 20:30:09 +00:00
|
|
|
* Laurent Jouanneau <laurent.jouanneau@disruptive-innovations.com>
|
2001-09-25 01:32:19 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
2004-04-17 21:52:36 +00:00
|
|
|
* either of 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"),
|
2001-09-25 01:32:19 +00:00
|
|
|
* 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
|
2004-04-17 21:52:36 +00:00
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
2001-09-25 01:32:19 +00:00
|
|
|
* 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
|
2004-04-17 21:52:36 +00:00
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
2001-09-25 01:32:19 +00:00
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2000-09-10 02:17:54 +00:00
|
|
|
|
2006-03-31 08:41:49 +00:00
|
|
|
/*
|
|
|
|
* nsIContentSerializer implementation that can be used with an
|
|
|
|
* nsIDocumentEncoder to convert an XML DOM to an XML string that
|
|
|
|
* could be parsed into more or less the original DOM.
|
|
|
|
*/
|
|
|
|
|
2000-09-10 02:17:54 +00:00
|
|
|
#include "nsXMLContentSerializer.h"
|
|
|
|
|
2007-01-30 00:06:41 +00:00
|
|
|
#include "nsGkAtoms.h"
|
2000-09-10 02:17:54 +00:00
|
|
|
#include "nsIDOMText.h"
|
|
|
|
#include "nsIDOMCDATASection.h"
|
|
|
|
#include "nsIDOMProcessingInstruction.h"
|
|
|
|
#include "nsIDOMComment.h"
|
2002-08-13 18:41:16 +00:00
|
|
|
#include "nsIDOMDocument.h"
|
2000-09-10 02:17:54 +00:00
|
|
|
#include "nsIDOMDocumentType.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDocument.h"
|
2008-10-21 20:30:09 +00:00
|
|
|
#include "nsIDocumentEncoder.h"
|
2000-09-10 02:17:54 +00:00
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsTextFragment.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
#include "prprf.h"
|
2001-12-17 07:14:49 +00:00
|
|
|
#include "nsUnicharUtils.h"
|
2002-05-15 18:55:21 +00:00
|
|
|
#include "nsCRT.h"
|
2002-11-29 23:44:07 +00:00
|
|
|
#include "nsContentUtils.h"
|
2005-12-28 21:52:39 +00:00
|
|
|
#include "nsAttrName.h"
|
2000-09-10 02:17:54 +00:00
|
|
|
|
2000-09-10 19:36:22 +00:00
|
|
|
nsresult NS_NewXMLContentSerializer(nsIContentSerializer** aSerializer)
|
|
|
|
{
|
|
|
|
nsXMLContentSerializer* it = new nsXMLContentSerializer();
|
|
|
|
if (!it) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
2002-12-11 14:24:49 +00:00
|
|
|
return CallQueryInterface(it, aSerializer);
|
2000-09-10 19:36:22 +00:00
|
|
|
}
|
|
|
|
|
2000-09-10 02:17:54 +00:00
|
|
|
nsXMLContentSerializer::nsXMLContentSerializer()
|
2003-10-23 22:24:21 +00:00
|
|
|
: mPrefixIndex(0),
|
2008-10-21 20:30:09 +00:00
|
|
|
mColPos(0),
|
2003-10-23 22:24:21 +00:00
|
|
|
mInAttribute(PR_FALSE),
|
|
|
|
mAddNewline(PR_FALSE)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXMLContentSerializer::~nsXMLContentSerializer()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS1(nsXMLContentSerializer, nsIContentSerializer)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2008-10-21 20:30:09 +00:00
|
|
|
nsXMLContentSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
|
2007-08-11 00:38:53 +00:00
|
|
|
const char* aCharSet, PRBool aIsCopying,
|
|
|
|
PRBool aIsWholeDocument)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
2006-11-28 04:01:46 +00:00
|
|
|
mCharset = aCharSet;
|
2008-10-21 20:30:09 +00:00
|
|
|
mFlags = aFlags;
|
|
|
|
|
|
|
|
// Set the line break character:
|
|
|
|
if ((mFlags & nsIDocumentEncoder::OutputCRLineBreak)
|
|
|
|
&& (mFlags & nsIDocumentEncoder::OutputLFLineBreak)) { // Windows
|
|
|
|
mLineBreak.AssignLiteral("\r\n");
|
|
|
|
}
|
|
|
|
else if (mFlags & nsIDocumentEncoder::OutputCRLineBreak) { // Mac
|
|
|
|
mLineBreak.AssignLiteral("\r");
|
|
|
|
}
|
|
|
|
else if (mFlags & nsIDocumentEncoder::OutputLFLineBreak) { // Unix/DOM
|
|
|
|
mLineBreak.AssignLiteral("\n");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mLineBreak.AssignLiteral(NS_LINEBREAK); // Platform/default
|
|
|
|
}
|
2000-09-10 02:17:54 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsXMLContentSerializer::AppendTextData(nsIDOMNode* aNode,
|
|
|
|
PRInt32 aStartOffset,
|
|
|
|
PRInt32 aEndOffset,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aStr,
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 10:57:30 +00:00
|
|
|
PRBool aTranslateEntities,
|
|
|
|
PRBool aIncrColumn)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
2006-07-19 04:36:36 +00:00
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
|
|
|
const nsTextFragment* frag;
|
|
|
|
if (!content || !(frag = content->GetText())) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2004-05-07 20:55:17 +00:00
|
|
|
|
|
|
|
PRInt32 endoffset = (aEndOffset == -1) ? frag->GetLength() : aEndOffset;
|
|
|
|
PRInt32 length = endoffset - aStartOffset;
|
|
|
|
|
|
|
|
NS_ASSERTION(aStartOffset >= 0, "Negative start offset for text fragment!");
|
|
|
|
NS_ASSERTION(aStartOffset <= endoffset, "A start offset is beyond the end of the text fragment!");
|
2002-03-13 06:20:15 +00:00
|
|
|
|
2004-05-07 20:55:17 +00:00
|
|
|
if (length <= 0) {
|
|
|
|
// XXX Zero is a legal value, maybe non-zero values should be an
|
|
|
|
// error.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-10-01 20:37:46 +00:00
|
|
|
|
2004-05-07 20:55:17 +00:00
|
|
|
if (frag->Is2b()) {
|
|
|
|
const PRUnichar *strStart = frag->Get2b() + aStartOffset;
|
|
|
|
AppendToString(Substring(strStart, strStart + length), aStr,
|
|
|
|
aTranslateEntities, aIncrColumn);
|
|
|
|
}
|
|
|
|
else {
|
2006-02-03 14:18:39 +00:00
|
|
|
AppendToString(NS_ConvertASCIItoUTF16(frag->Get1b()+aStartOffset, length),
|
2004-05-07 20:55:17 +00:00
|
|
|
aStr, aTranslateEntities, aIncrColumn);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2000-09-10 22:22:58 +00:00
|
|
|
|
2000-09-10 02:17:54 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLContentSerializer::AppendText(nsIDOMText* aText,
|
|
|
|
PRInt32 aStartOffset,
|
|
|
|
PRInt32 aEndOffset,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aStr)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aText);
|
|
|
|
|
2008-10-21 20:30:09 +00:00
|
|
|
nsAutoString data;
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
rv = AppendTextData(aText, aStartOffset, aEndOffset, data, PR_TRUE, PR_TRUE);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
AppendToStringConvertLF(data, aStr);
|
|
|
|
|
|
|
|
return NS_OK;
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLContentSerializer::AppendCDATASection(nsIDOMCDATASection* aCDATASection,
|
|
|
|
PRInt32 aStartOffset,
|
|
|
|
PRInt32 aEndOffset,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aStr)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aCDATASection);
|
|
|
|
nsresult rv;
|
|
|
|
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("<![CDATA["), aStr);
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 10:57:30 +00:00
|
|
|
rv = AppendTextData(aCDATASection, aStartOffset, aEndOffset, aStr, PR_FALSE, PR_TRUE);
|
2000-09-10 02:17:54 +00:00
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("]]>"), aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLContentSerializer::AppendProcessingInstruction(nsIDOMProcessingInstruction* aPI,
|
|
|
|
PRInt32 aStartOffset,
|
|
|
|
PRInt32 aEndOffset,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aStr)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aPI);
|
|
|
|
nsresult rv;
|
|
|
|
nsAutoString target, data;
|
|
|
|
|
2003-10-23 22:24:21 +00:00
|
|
|
MaybeAddNewline(aStr);
|
|
|
|
|
2000-09-10 02:17:54 +00:00
|
|
|
rv = aPI->GetTarget(target);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
rv = aPI->GetData(data);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("<?"), aStr);
|
|
|
|
AppendToString(target, aStr);
|
2002-01-24 02:03:19 +00:00
|
|
|
if (!data.IsEmpty()) {
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING(" "), aStr);
|
2008-10-21 20:30:09 +00:00
|
|
|
AppendToStringConvertLF(data, aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2000-12-27 23:48:10 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("?>"), aStr);
|
2003-10-23 22:24:21 +00:00
|
|
|
MaybeFlagNewline(aPI);
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLContentSerializer::AppendComment(nsIDOMComment* aComment,
|
|
|
|
PRInt32 aStartOffset,
|
|
|
|
PRInt32 aEndOffset,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aStr)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aComment);
|
|
|
|
nsresult rv;
|
|
|
|
nsAutoString data;
|
|
|
|
|
|
|
|
rv = aComment->GetData(data);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
2003-10-23 22:24:21 +00:00
|
|
|
MaybeAddNewline(aStr);
|
|
|
|
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("<!--"), aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
if (aStartOffset || (aEndOffset != -1)) {
|
|
|
|
PRInt32 length = (aEndOffset == -1) ? data.Length() : aEndOffset;
|
|
|
|
length -= aStartOffset;
|
|
|
|
|
|
|
|
nsAutoString frag;
|
|
|
|
data.Mid(frag, aStartOffset, length);
|
2008-10-21 20:30:09 +00:00
|
|
|
AppendToStringConvertLF(frag, aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
else {
|
2008-10-21 20:30:09 +00:00
|
|
|
AppendToStringConvertLF(data, aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("-->"), aStr);
|
2003-10-23 22:24:21 +00:00
|
|
|
MaybeFlagNewline(aComment);
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLContentSerializer::AppendDoctype(nsIDOMDocumentType *aDoctype,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aStr)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aDoctype);
|
|
|
|
nsresult rv;
|
|
|
|
nsAutoString name, publicId, systemId, internalSubset;
|
|
|
|
|
|
|
|
rv = aDoctype->GetName(name);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
rv = aDoctype->GetPublicId(publicId);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
rv = aDoctype->GetSystemId(systemId);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 10:57:30 +00:00
|
|
|
rv = aDoctype->GetInternalSubset(internalSubset);
|
2000-09-10 02:17:54 +00:00
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
|
|
|
|
2003-10-23 22:24:21 +00:00
|
|
|
MaybeAddNewline(aStr);
|
|
|
|
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("<!DOCTYPE "), aStr);
|
|
|
|
AppendToString(name, aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
PRUnichar quote;
|
2002-01-24 02:03:19 +00:00
|
|
|
if (!publicId.IsEmpty()) {
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING(" PUBLIC "), aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
if (publicId.FindChar(PRUnichar('"')) == -1) {
|
|
|
|
quote = PRUnichar('"');
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
quote = PRUnichar('\'');
|
|
|
|
}
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(quote, aStr);
|
|
|
|
AppendToString(publicId, aStr);
|
|
|
|
AppendToString(quote, aStr);
|
2000-10-13 11:06:05 +00:00
|
|
|
|
2002-01-24 02:03:19 +00:00
|
|
|
if (!systemId.IsEmpty()) {
|
2000-10-13 11:06:05 +00:00
|
|
|
AppendToString(PRUnichar(' '), aStr);
|
|
|
|
if (systemId.FindChar(PRUnichar('"')) == -1) {
|
|
|
|
quote = PRUnichar('"');
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
quote = PRUnichar('\'');
|
|
|
|
}
|
|
|
|
AppendToString(quote, aStr);
|
|
|
|
AppendToString(systemId, aStr);
|
|
|
|
AppendToString(quote, aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
}
|
2002-01-24 02:03:19 +00:00
|
|
|
else if (!systemId.IsEmpty()) {
|
2000-09-10 02:17:54 +00:00
|
|
|
if (systemId.FindChar(PRUnichar('"')) == -1) {
|
|
|
|
quote = PRUnichar('"');
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
quote = PRUnichar('\'');
|
|
|
|
}
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING(" SYSTEM "), aStr);
|
|
|
|
AppendToString(quote, aStr);
|
|
|
|
AppendToString(systemId, aStr);
|
|
|
|
AppendToString(quote, aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
|
2002-01-24 02:03:19 +00:00
|
|
|
if (!internalSubset.IsEmpty()) {
|
2003-03-07 23:40:51 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING(" ["), aStr);
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(internalSubset, aStr);
|
2003-03-07 23:40:51 +00:00
|
|
|
AppendToString(PRUnichar(']'), aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
|
2003-03-07 23:40:51 +00:00
|
|
|
AppendToString(PRUnichar('>'), aStr);
|
2003-10-23 22:24:21 +00:00
|
|
|
MaybeFlagNewline(aDoctype);
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-09-16 12:39:49 +00:00
|
|
|
#define kXMLNS "xmlns"
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
nsresult
|
2002-03-23 23:54:46 +00:00
|
|
|
nsXMLContentSerializer::PushNameSpaceDecl(const nsAString& aPrefix,
|
|
|
|
const nsAString& aURI,
|
2000-09-10 02:17:54 +00:00
|
|
|
nsIDOMElement* aOwner)
|
|
|
|
{
|
2009-03-26 08:29:49 +00:00
|
|
|
NameSpaceDecl* decl = mNameSpaceStack.AppendElement();
|
2000-09-10 02:17:54 +00:00
|
|
|
if (!decl) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
decl->mPrefix.Assign(aPrefix);
|
|
|
|
decl->mURI.Assign(aURI);
|
|
|
|
// Don't addref - this weak reference will be removed when
|
|
|
|
// we pop the stack
|
|
|
|
decl->mOwner = aOwner;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXMLContentSerializer::PopNameSpaceDeclsFor(nsIDOMElement* aOwner)
|
|
|
|
{
|
|
|
|
PRInt32 index, count;
|
|
|
|
|
2009-03-20 08:15:35 +00:00
|
|
|
count = mNameSpaceStack.Length();
|
2000-12-27 23:48:10 +00:00
|
|
|
for (index = count - 1; index >= 0; index--) {
|
2009-03-26 08:29:49 +00:00
|
|
|
if (mNameSpaceStack[index].mOwner != aOwner) {
|
2000-12-27 23:48:10 +00:00
|
|
|
break;
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2000-12-27 23:48:10 +00:00
|
|
|
mNameSpaceStack.RemoveElementAt(index);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
2002-03-23 23:54:46 +00:00
|
|
|
nsXMLContentSerializer::ConfirmPrefix(nsAString& aPrefix,
|
2004-10-13 01:16:06 +00:00
|
|
|
const nsAString& aURI,
|
|
|
|
nsIDOMElement* aElement,
|
2005-11-29 16:23:27 +00:00
|
|
|
PRBool aIsAttribute)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
2006-04-17 17:13:11 +00:00
|
|
|
if (aPrefix.EqualsLiteral(kXMLNS)) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aURI.EqualsLiteral("http://www.w3.org/XML/1998/namespace")) {
|
|
|
|
// The prefix must be xml for this namespace. We don't need to declare it,
|
|
|
|
// so always just set the prefix to xml.
|
|
|
|
aPrefix.AssignLiteral("xml");
|
|
|
|
|
2000-09-10 02:17:54 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2005-11-29 16:23:27 +00:00
|
|
|
|
|
|
|
PRBool mustHavePrefix;
|
|
|
|
if (aIsAttribute) {
|
|
|
|
if (aURI.IsEmpty()) {
|
|
|
|
// Attribute in the null namespace. This just shouldn't have a prefix.
|
|
|
|
// And there's no need to push any namespace decls
|
|
|
|
aPrefix.Truncate();
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attribute not in the null namespace -- must have a prefix
|
|
|
|
mustHavePrefix = PR_TRUE;
|
|
|
|
} else {
|
|
|
|
// Not an attribute, so doesn't _have_ to have a prefix
|
|
|
|
mustHavePrefix = PR_FALSE;
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2004-10-13 01:16:06 +00:00
|
|
|
|
2005-11-29 16:23:27 +00:00
|
|
|
// Keep track of the closest prefix that's bound to aURI and whether we've
|
|
|
|
// found such a thing. closestURIMatch holds the prefix, and uriMatch
|
|
|
|
// indicates whether we actually have one.
|
2000-09-10 02:17:54 +00:00
|
|
|
nsAutoString closestURIMatch;
|
|
|
|
PRBool uriMatch = PR_FALSE;
|
|
|
|
|
2005-11-29 16:23:27 +00:00
|
|
|
// Also keep track of whether we've seen aPrefix already. If we have, that
|
|
|
|
// means that it's already bound to a URI different from aURI, so even if we
|
|
|
|
// later (so in a more outer scope) see it bound to aURI we can't reuse it.
|
|
|
|
PRBool haveSeenOurPrefix = PR_FALSE;
|
|
|
|
|
2009-03-20 08:15:35 +00:00
|
|
|
PRInt32 count = mNameSpaceStack.Length();
|
2004-10-13 01:16:06 +00:00
|
|
|
PRInt32 index = count - 1;
|
|
|
|
while (index >= 0) {
|
2009-03-26 08:29:49 +00:00
|
|
|
NameSpaceDecl& decl = mNameSpaceStack.ElementAt(index);
|
2000-12-27 23:48:10 +00:00
|
|
|
// Check if we've found a prefix match
|
2009-03-26 08:29:49 +00:00
|
|
|
if (aPrefix.Equals(decl.mPrefix)) {
|
2005-11-29 16:23:27 +00:00
|
|
|
|
|
|
|
// If the URIs match and aPrefix is not bound to any other URI, we can
|
|
|
|
// use aPrefix
|
2009-03-26 08:29:49 +00:00
|
|
|
if (!haveSeenOurPrefix && aURI.Equals(decl.mURI)) {
|
2005-11-29 16:23:27 +00:00
|
|
|
// Just use our uriMatch stuff. That will deal with an empty aPrefix
|
|
|
|
// the right way. We can break out of the loop now, though.
|
|
|
|
uriMatch = PR_TRUE;
|
|
|
|
closestURIMatch = aPrefix;
|
|
|
|
break;
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2004-10-13 01:16:06 +00:00
|
|
|
|
2005-11-29 16:23:27 +00:00
|
|
|
haveSeenOurPrefix = PR_TRUE;
|
|
|
|
|
2004-10-13 01:16:06 +00:00
|
|
|
// If they don't, and either:
|
|
|
|
// 1) We have a prefix (so we'd be redeclaring this prefix to point to a
|
|
|
|
// different namespace) or
|
|
|
|
// 2) We're looking at an existing default namespace decl on aElement (so
|
|
|
|
// we can't create a new default namespace decl for this URI)
|
|
|
|
// then generate a new prefix. Note that we do NOT generate new prefixes
|
|
|
|
// if we happen to have aPrefix == decl->mPrefix == "" and mismatching
|
|
|
|
// URIs when |decl| doesn't have aElement as its owner. In that case we
|
|
|
|
// can simply push the new namespace URI as the default namespace for
|
|
|
|
// aElement.
|
2009-03-26 08:29:49 +00:00
|
|
|
if (!aPrefix.IsEmpty() || decl.mOwner == aElement) {
|
2006-02-18 13:01:59 +00:00
|
|
|
NS_ASSERTION(!aURI.IsEmpty(),
|
|
|
|
"Not allowed to add a xmlns attribute with an empty "
|
|
|
|
"namespace name unless it declares the default "
|
|
|
|
"namespace.");
|
|
|
|
|
2004-10-13 01:16:06 +00:00
|
|
|
GenerateNewPrefix(aPrefix);
|
|
|
|
// Now we need to validate our new prefix/uri combination; check it
|
|
|
|
// against the full namespace stack again. Note that just restarting
|
|
|
|
// the while loop is ok, since we haven't changed aURI, so the
|
2005-11-29 16:23:27 +00:00
|
|
|
// closestURIMatch and uriMatch state is not affected.
|
2004-10-13 01:16:06 +00:00
|
|
|
index = count - 1;
|
2005-11-29 16:23:27 +00:00
|
|
|
haveSeenOurPrefix = PR_FALSE;
|
2004-10-13 01:16:06 +00:00
|
|
|
continue;
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
}
|
2004-10-13 01:16:06 +00:00
|
|
|
|
2000-12-27 23:48:10 +00:00
|
|
|
// If we've found a URI match, then record the first one
|
2009-03-26 08:29:49 +00:00
|
|
|
if (!uriMatch && aURI.Equals(decl.mURI)) {
|
2004-10-13 01:16:06 +00:00
|
|
|
// Need to check that decl->mPrefix is not declared anywhere closer to
|
|
|
|
// us. If it is, we can't use it.
|
|
|
|
PRBool prefixOK = PR_TRUE;
|
|
|
|
PRInt32 index2;
|
|
|
|
for (index2 = count-1; index2 > index && prefixOK; --index2) {
|
2009-03-26 08:29:49 +00:00
|
|
|
prefixOK = (mNameSpaceStack[index2].mPrefix != decl.mPrefix);
|
2004-10-13 01:16:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (prefixOK) {
|
|
|
|
uriMatch = PR_TRUE;
|
2009-03-26 08:29:49 +00:00
|
|
|
closestURIMatch.Assign(decl.mPrefix);
|
2004-10-13 01:16:06 +00:00
|
|
|
}
|
2000-12-27 23:48:10 +00:00
|
|
|
}
|
2004-10-13 01:16:06 +00:00
|
|
|
|
|
|
|
--index;
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
|
2004-10-13 01:16:06 +00:00
|
|
|
// At this point the following invariants hold:
|
2005-11-29 16:23:27 +00:00
|
|
|
// 1) The prefix in closestURIMatch is mapped to aURI in our scope if
|
|
|
|
// uriMatch is set.
|
2004-10-13 01:16:06 +00:00
|
|
|
// 2) There is nothing on the namespace stack that has aPrefix as the prefix
|
|
|
|
// and a _different_ URI, except for the case aPrefix.IsEmpty (and
|
|
|
|
// possible default namespaces on ancestors)
|
|
|
|
|
|
|
|
// So if uriMatch is set it's OK to use the closestURIMatch prefix. The one
|
|
|
|
// exception is when closestURIMatch is actually empty (default namespace
|
|
|
|
// decl) and we must have a prefix.
|
2005-11-29 16:23:27 +00:00
|
|
|
if (uriMatch && (!mustHavePrefix || !closestURIMatch.IsEmpty())) {
|
2000-09-10 02:17:54 +00:00
|
|
|
aPrefix.Assign(closestURIMatch);
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2004-10-13 01:16:06 +00:00
|
|
|
|
2005-11-29 16:23:27 +00:00
|
|
|
if (aPrefix.IsEmpty()) {
|
|
|
|
// At this point, aPrefix is empty (which means we never had a prefix to
|
|
|
|
// start with). If we must have a prefix, just generate a new prefix and
|
|
|
|
// then send it back through the namespace stack checks to make sure it's
|
|
|
|
// OK.
|
|
|
|
if (mustHavePrefix) {
|
|
|
|
GenerateNewPrefix(aPrefix);
|
|
|
|
return ConfirmPrefix(aPrefix, aURI, aElement, aIsAttribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
// One final special case. If aPrefix is empty and we never saw an empty
|
|
|
|
// prefix (default namespace decl) on the namespace stack and we're in the
|
|
|
|
// null namespace there is no reason to output an |xmlns=""| here. It just
|
|
|
|
// makes the output less readable.
|
|
|
|
if (!haveSeenOurPrefix && aURI.IsEmpty()) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
|
2005-11-29 16:23:27 +00:00
|
|
|
// Now just set aURI as the new default namespace URI. Indicate that we need
|
|
|
|
// to create a namespace decl for the final prefix
|
2000-09-10 02:17:54 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2004-10-13 01:16:06 +00:00
|
|
|
void
|
|
|
|
nsXMLContentSerializer::GenerateNewPrefix(nsAString& aPrefix)
|
|
|
|
{
|
|
|
|
aPrefix.AssignLiteral("a");
|
|
|
|
char buf[128];
|
|
|
|
PR_snprintf(buf, sizeof(buf), "%d", mPrefixIndex++);
|
|
|
|
AppendASCIItoUTF16(buf, aPrefix);
|
|
|
|
}
|
|
|
|
|
2000-09-10 02:17:54 +00:00
|
|
|
void
|
2002-03-23 23:54:46 +00:00
|
|
|
nsXMLContentSerializer::SerializeAttr(const nsAString& aPrefix,
|
|
|
|
const nsAString& aName,
|
|
|
|
const nsAString& aValue,
|
|
|
|
nsAString& aStr,
|
2001-06-19 23:51:29 +00:00
|
|
|
PRBool aDoEscapeEntities)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(PRUnichar(' '), aStr);
|
2002-01-24 02:03:19 +00:00
|
|
|
if (!aPrefix.IsEmpty()) {
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(aPrefix, aStr);
|
2003-04-21 04:15:58 +00:00
|
|
|
AppendToString(PRUnichar(':'), aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(aName, aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
|
2003-04-21 04:15:58 +00:00
|
|
|
if ( aDoEscapeEntities ) {
|
|
|
|
// if problem characters are turned into character entity references
|
|
|
|
// then there will be no problem with the value delimiter characters
|
|
|
|
AppendToString(NS_LITERAL_STRING("=\""), aStr);
|
2000-10-13 11:06:05 +00:00
|
|
|
|
2003-04-21 04:15:58 +00:00
|
|
|
mInAttribute = PR_TRUE;
|
|
|
|
AppendToString(aValue, aStr, PR_TRUE);
|
|
|
|
mInAttribute = PR_FALSE;
|
|
|
|
|
|
|
|
AppendToString(PRUnichar('"'), aStr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Depending on whether the attribute value contains quotes or apostrophes we
|
|
|
|
// need to select the delimiter character and escape characters using
|
|
|
|
// character entity references, ignoring the value of aDoEscapeEntities.
|
|
|
|
// See http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2.2 for
|
2007-09-14 19:03:13 +00:00
|
|
|
// the standard on character entity references in values. We also have to
|
|
|
|
// make sure to escape any '&' characters.
|
|
|
|
|
2003-04-21 04:15:58 +00:00
|
|
|
PRBool bIncludesSingle = PR_FALSE;
|
|
|
|
PRBool bIncludesDouble = PR_FALSE;
|
|
|
|
nsAString::const_iterator iCurr, iEnd;
|
|
|
|
PRUint32 uiSize, i;
|
|
|
|
aValue.BeginReading(iCurr);
|
|
|
|
aValue.EndReading(iEnd);
|
|
|
|
for ( ; iCurr != iEnd; iCurr.advance(uiSize) ) {
|
|
|
|
const PRUnichar * buf = iCurr.get();
|
|
|
|
uiSize = iCurr.size_forward();
|
|
|
|
for ( i = 0; i < uiSize; i++, buf++ ) {
|
|
|
|
if ( *buf == PRUnichar('\'') )
|
|
|
|
{
|
|
|
|
bIncludesSingle = PR_TRUE;
|
|
|
|
if ( bIncludesDouble ) break;
|
|
|
|
}
|
|
|
|
else if ( *buf == PRUnichar('"') )
|
|
|
|
{
|
|
|
|
bIncludesDouble = PR_TRUE;
|
|
|
|
if ( bIncludesSingle ) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if both have been found we don't need to search further
|
|
|
|
if ( bIncludesDouble && bIncludesSingle ) break;
|
|
|
|
}
|
2000-10-13 11:06:05 +00:00
|
|
|
|
2003-04-21 04:15:58 +00:00
|
|
|
// Delimiter and escaping is according to the following table
|
|
|
|
// bIncludesDouble bIncludesSingle Delimiter Escape Double Quote
|
|
|
|
// FALSE FALSE " FALSE
|
|
|
|
// FALSE TRUE " FALSE
|
|
|
|
// TRUE FALSE ' FALSE
|
|
|
|
// TRUE TRUE " TRUE
|
|
|
|
PRUnichar cDelimiter =
|
|
|
|
(bIncludesDouble && !bIncludesSingle) ? PRUnichar('\'') : PRUnichar('"');
|
|
|
|
AppendToString(PRUnichar('='), aStr);
|
|
|
|
AppendToString(cDelimiter, aStr);
|
2007-09-14 19:03:13 +00:00
|
|
|
nsAutoString sValue(aValue);
|
|
|
|
sValue.ReplaceSubstring(NS_LITERAL_STRING("&"),
|
|
|
|
NS_LITERAL_STRING("&"));
|
2003-04-21 04:15:58 +00:00
|
|
|
if (bIncludesDouble && bIncludesSingle) {
|
2007-09-14 19:03:13 +00:00
|
|
|
sValue.ReplaceSubstring(NS_LITERAL_STRING("\""),
|
|
|
|
NS_LITERAL_STRING("""));
|
2003-04-21 04:15:58 +00:00
|
|
|
}
|
2007-09-14 19:03:13 +00:00
|
|
|
mInAttribute = PR_TRUE;
|
|
|
|
AppendToString(sValue, aStr, PR_FALSE);
|
|
|
|
mInAttribute = PR_FALSE;
|
2003-04-21 04:15:58 +00:00
|
|
|
AppendToString(cDelimiter, aStr);
|
|
|
|
}
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLContentSerializer::AppendElementStart(nsIDOMElement *aElement,
|
2006-04-06 20:55:25 +00:00
|
|
|
nsIDOMElement *aOriginalElement,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aStr)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aElement);
|
|
|
|
|
|
|
|
nsAutoString tagPrefix, tagLocalName, tagNamespaceURI;
|
2000-12-27 23:48:10 +00:00
|
|
|
nsAutoString xmlnsStr;
|
2004-09-16 12:39:49 +00:00
|
|
|
xmlnsStr.AssignLiteral(kXMLNS);
|
2000-12-27 23:48:10 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
|
|
|
|
if (!content) return NS_ERROR_FAILURE;
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
aElement->GetPrefix(tagPrefix);
|
|
|
|
aElement->GetLocalName(tagLocalName);
|
|
|
|
aElement->GetNamespaceURI(tagNamespaceURI);
|
|
|
|
|
2003-09-27 04:18:26 +00:00
|
|
|
PRUint32 index, count;
|
2000-09-10 02:17:54 +00:00
|
|
|
nsAutoString nameStr, prefixStr, uriStr, valueStr;
|
|
|
|
|
2003-09-27 04:18:26 +00:00
|
|
|
count = content->GetAttrCount();
|
|
|
|
|
2000-09-10 02:17:54 +00:00
|
|
|
// First scan for namespace declarations, pushing each on the stack
|
2006-02-18 13:01:59 +00:00
|
|
|
PRUint32 skipAttr = count;
|
2000-09-10 02:17:54 +00:00
|
|
|
for (index = 0; index < count; index++) {
|
|
|
|
|
2005-12-28 21:52:39 +00:00
|
|
|
const nsAttrName* name = content->GetAttrNameAt(index);
|
|
|
|
PRInt32 namespaceID = name->NamespaceID();
|
|
|
|
nsIAtom *attrName = name->LocalName();
|
2000-09-10 02:17:54 +00:00
|
|
|
|
2004-10-13 01:16:06 +00:00
|
|
|
if (namespaceID == kNameSpaceID_XMLNS ||
|
|
|
|
// Also push on the stack attrs named "xmlns" in the null
|
|
|
|
// namespace... because once we serialize those out they'll look like
|
|
|
|
// namespace decls. :(
|
|
|
|
// XXXbz what if we have both "xmlns" in the null namespace and "xmlns"
|
|
|
|
// in the xmlns namespace?
|
|
|
|
(namespaceID == kNameSpaceID_None &&
|
2006-12-26 17:47:52 +00:00
|
|
|
attrName == nsGkAtoms::xmlns)) {
|
2001-08-17 08:14:14 +00:00
|
|
|
content->GetAttr(namespaceID, attrName, uriStr);
|
2000-12-27 23:48:10 +00:00
|
|
|
|
2005-12-28 21:52:39 +00:00
|
|
|
if (!name->GetPrefix()) {
|
2006-02-18 13:01:59 +00:00
|
|
|
if (tagNamespaceURI.IsEmpty() && !uriStr.IsEmpty()) {
|
|
|
|
// If the element is in no namespace we need to add a xmlns
|
|
|
|
// attribute to declare that. That xmlns attribute must not have a
|
|
|
|
// prefix (see http://www.w3.org/TR/REC-xml-names/#dt-prefix), ie it
|
|
|
|
// must declare the default namespace. We just found an xmlns
|
|
|
|
// attribute that declares the default namespace to something
|
|
|
|
// non-empty. We're going to ignore this attribute, for children we
|
|
|
|
// will detect that we need to add it again and attributes aren't
|
|
|
|
// affected by the default namespace.
|
|
|
|
skipAttr = index;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Default NS attribute does not have prefix (and the name is "xmlns")
|
2006-04-06 20:55:25 +00:00
|
|
|
PushNameSpaceDecl(EmptyString(), uriStr, aOriginalElement);
|
2006-02-18 13:01:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2002-03-27 00:13:57 +00:00
|
|
|
attrName->ToString(nameStr);
|
2006-04-06 20:55:25 +00:00
|
|
|
PushNameSpaceDecl(nameStr, uriStr, aOriginalElement);
|
2000-12-27 23:48:10 +00:00
|
|
|
}
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool addNSAttr;
|
|
|
|
|
2003-10-23 22:24:21 +00:00
|
|
|
MaybeAddNewline(aStr);
|
|
|
|
|
2006-04-06 20:55:25 +00:00
|
|
|
addNSAttr = ConfirmPrefix(tagPrefix, tagNamespaceURI, aOriginalElement,
|
|
|
|
PR_FALSE);
|
2000-12-27 23:48:10 +00:00
|
|
|
// Serialize the qualified name of the element
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("<"), aStr);
|
2002-03-27 00:13:57 +00:00
|
|
|
if (!tagPrefix.IsEmpty()) {
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(tagPrefix, aStr);
|
|
|
|
AppendToString(NS_LITERAL_STRING(":"), aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(tagLocalName, aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
// If we had to add a new namespace declaration, serialize
|
|
|
|
// and push it on the namespace stack
|
|
|
|
if (addNSAttr) {
|
2004-10-13 01:16:06 +00:00
|
|
|
if (tagPrefix.IsEmpty()) {
|
|
|
|
// Serialize default namespace decl
|
|
|
|
SerializeAttr(EmptyString(), xmlnsStr, tagNamespaceURI, aStr, PR_TRUE);
|
|
|
|
} else {
|
|
|
|
// Serialize namespace decl
|
|
|
|
SerializeAttr(xmlnsStr, tagPrefix, tagNamespaceURI, aStr, PR_TRUE);
|
|
|
|
}
|
2006-04-06 20:55:25 +00:00
|
|
|
PushNameSpaceDecl(tagPrefix, tagNamespaceURI, aOriginalElement);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now serialize each of the attributes
|
|
|
|
// XXX Unfortunately we need a namespace manager to get
|
|
|
|
// attribute URIs.
|
|
|
|
for (index = 0; index < count; index++) {
|
2006-02-18 13:01:59 +00:00
|
|
|
if (skipAttr == index) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-12-28 21:52:39 +00:00
|
|
|
const nsAttrName* name = content->GetAttrNameAt(index);
|
|
|
|
PRInt32 namespaceID = name->NamespaceID();
|
|
|
|
nsIAtom* attrName = name->LocalName();
|
|
|
|
nsIAtom* attrPrefix = name->GetPrefix();
|
2002-04-09 04:12:01 +00:00
|
|
|
|
2000-09-10 02:17:54 +00:00
|
|
|
if (attrPrefix) {
|
|
|
|
attrPrefix->ToString(prefixStr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
prefixStr.Truncate();
|
|
|
|
}
|
|
|
|
|
|
|
|
addNSAttr = PR_FALSE;
|
2002-11-29 23:44:07 +00:00
|
|
|
if (kNameSpaceID_XMLNS != namespaceID) {
|
2005-09-11 10:08:43 +00:00
|
|
|
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr);
|
2006-04-06 20:55:25 +00:00
|
|
|
addNSAttr = ConfirmPrefix(prefixStr, uriStr, aOriginalElement, PR_TRUE);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2000-12-27 23:48:10 +00:00
|
|
|
|
2001-08-17 08:14:14 +00:00
|
|
|
content->GetAttr(namespaceID, attrName, valueStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
attrName->ToString(nameStr);
|
2002-04-09 04:12:01 +00:00
|
|
|
|
|
|
|
// XXX Hack to get around the fact that MathML can add
|
|
|
|
// attributes starting with '-', which makes them
|
|
|
|
// invalid XML.
|
|
|
|
if (!nameStr.IsEmpty() && nameStr.First() == '-')
|
|
|
|
continue;
|
|
|
|
|
2002-05-28 12:34:48 +00:00
|
|
|
if (namespaceID == kNameSpaceID_None) {
|
2004-12-13 04:14:28 +00:00
|
|
|
if (content->GetNameSpaceID() == kNameSpaceID_XHTML) {
|
2003-11-19 01:20:56 +00:00
|
|
|
if (IsShorthandAttr(attrName, content->Tag()) &&
|
2002-05-28 12:34:48 +00:00
|
|
|
valueStr.IsEmpty()) {
|
|
|
|
valueStr = nameStr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-06-19 23:51:29 +00:00
|
|
|
SerializeAttr(prefixStr, nameStr, valueStr, aStr, PR_TRUE);
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
if (addNSAttr) {
|
2004-10-13 01:16:06 +00:00
|
|
|
NS_ASSERTION(!prefixStr.IsEmpty(),
|
|
|
|
"Namespaced attributes must have a prefix");
|
2001-06-19 23:51:29 +00:00
|
|
|
SerializeAttr(xmlnsStr, prefixStr, uriStr, aStr, PR_TRUE);
|
2006-04-06 20:55:25 +00:00
|
|
|
PushNameSpaceDecl(prefixStr, uriStr, aOriginalElement);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-12-27 23:48:10 +00:00
|
|
|
// We don't output a separate end tag for empty element
|
2006-04-06 20:55:25 +00:00
|
|
|
PRBool hasChildren;
|
|
|
|
if (NS_FAILED(aOriginalElement->HasChildNodes(&hasChildren)) ||
|
|
|
|
!hasChildren) {
|
2000-12-27 23:48:10 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("/>"), aStr);
|
2003-10-23 22:24:21 +00:00
|
|
|
MaybeFlagNewline(aElement);
|
2000-12-27 23:48:10 +00:00
|
|
|
} else {
|
|
|
|
AppendToString(NS_LITERAL_STRING(">"), aStr);
|
|
|
|
}
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLContentSerializer::AppendElementEnd(nsIDOMElement *aElement,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aStr)
|
2000-09-10 02:17:54 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aElement);
|
|
|
|
|
2000-12-27 23:48:10 +00:00
|
|
|
// We don't output a separate end tag for empty element
|
|
|
|
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aElement));
|
|
|
|
PRBool hasChildren;
|
|
|
|
if (NS_SUCCEEDED(node->HasChildNodes(&hasChildren)) && !hasChildren) {
|
2004-07-22 14:46:38 +00:00
|
|
|
PopNameSpaceDeclsFor(aElement);
|
|
|
|
|
2000-12-27 23:48:10 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
|
|
|
|
if (!content) return NS_ERROR_FAILURE;
|
|
|
|
|
2000-09-10 02:17:54 +00:00
|
|
|
nsAutoString tagPrefix, tagLocalName, tagNamespaceURI;
|
|
|
|
|
|
|
|
aElement->GetPrefix(tagPrefix);
|
|
|
|
aElement->GetLocalName(tagLocalName);
|
|
|
|
aElement->GetNamespaceURI(tagNamespaceURI);
|
|
|
|
|
2004-10-13 01:16:06 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
PRBool debugNeedToPushNamespace =
|
|
|
|
#endif
|
|
|
|
ConfirmPrefix(tagPrefix, tagNamespaceURI, aElement, PR_FALSE);
|
|
|
|
NS_ASSERTION(!debugNeedToPushNamespace, "Can't push namespaces in closing tag!");
|
2000-12-27 23:48:10 +00:00
|
|
|
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(NS_LITERAL_STRING("</"), aStr);
|
2002-03-27 00:13:57 +00:00
|
|
|
if (!tagPrefix.IsEmpty()) {
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(tagPrefix, aStr);
|
|
|
|
AppendToString(NS_LITERAL_STRING(":"), aStr);
|
2000-09-10 02:17:54 +00:00
|
|
|
}
|
2000-09-10 22:22:58 +00:00
|
|
|
AppendToString(tagLocalName, aStr);
|
|
|
|
AppendToString(NS_LITERAL_STRING(">"), aStr);
|
2003-10-23 22:24:21 +00:00
|
|
|
MaybeFlagNewline(aElement);
|
2000-09-10 02:17:54 +00:00
|
|
|
|
|
|
|
PopNameSpaceDeclsFor(aElement);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-09-10 22:22:58 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
nsXMLContentSerializer::AppendToString(const PRUnichar* aStr,
|
|
|
|
PRInt32 aLength,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aOutputStr)
|
2000-09-10 22:22:58 +00:00
|
|
|
{
|
|
|
|
PRInt32 length = (aLength == -1) ? nsCRT::strlen(aStr) : aLength;
|
|
|
|
|
|
|
|
aOutputStr.Append(aStr, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXMLContentSerializer::AppendToString(const PRUnichar aChar,
|
2002-03-23 23:54:46 +00:00
|
|
|
nsAString& aOutputStr)
|
2000-09-10 22:22:58 +00:00
|
|
|
{
|
|
|
|
aOutputStr.Append(aChar);
|
|
|
|
}
|
|
|
|
|
2003-05-27 03:49:22 +00:00
|
|
|
static const PRUint16 kGTVal = 62;
|
2000-09-10 22:22:58 +00:00
|
|
|
static const char* kEntities[] = {
|
2000-10-13 11:06:05 +00:00
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
|
|
|
"", "", "", "", "", "", "", "", "&", "",
|
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
|
|
|
"<", "", ">"
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char* kAttrEntities[] = {
|
2000-09-10 22:22:58 +00:00
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
2002-03-04 10:06:59 +00:00
|
|
|
"", "", "", "", """, "", "", "", "&", "",
|
2000-09-10 22:22:58 +00:00
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
|
|
|
"", "", "", "", "", "", "", "", "", "",
|
|
|
|
"<", "", ">"
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2002-03-23 23:54:46 +00:00
|
|
|
nsXMLContentSerializer::AppendToString(const nsAString& aStr,
|
|
|
|
nsAString& aOutputStr,
|
Checking in for bug 50742, this change removes the use of XIF in mozilla and replaces the XIF converter with a HTML (and XML) serializer.
Contextual information added to HTML copy and intelligence added to HTML paste in the editor (fixes bugs 47014, 50568 and 46554, and partly (at least) fixes bug 53188).
Code written by vidur, jfrancis, jst, akkana. Tested by jfrancis, akkana, vidur, jst, kin. Reviwed (and super reviewed) by waterson, vidur, kin, jfrancis, jst
2000-10-07 10:57:30 +00:00
|
|
|
PRBool aTranslateEntities,
|
|
|
|
PRBool aIncrColumn)
|
2000-09-10 22:22:58 +00:00
|
|
|
{
|
|
|
|
if (aTranslateEntities) {
|
|
|
|
nsReadingIterator<PRUnichar> done_reading;
|
|
|
|
aStr.EndReading(done_reading);
|
|
|
|
|
|
|
|
// for each chunk of |aString|...
|
|
|
|
PRUint32 advanceLength = 0;
|
|
|
|
nsReadingIterator<PRUnichar> iter;
|
2000-10-13 11:06:05 +00:00
|
|
|
|
|
|
|
const char **entityTable = mInAttribute ? kAttrEntities : kEntities;
|
|
|
|
|
2000-09-10 22:22:58 +00:00
|
|
|
for (aStr.BeginReading(iter);
|
|
|
|
iter != done_reading;
|
|
|
|
iter.advance(PRInt32(advanceLength))) {
|
|
|
|
PRUint32 fragmentLength = iter.size_forward();
|
|
|
|
const PRUnichar* c = iter.get();
|
|
|
|
const PRUnichar* fragmentStart = c;
|
|
|
|
const PRUnichar* fragmentEnd = c + fragmentLength;
|
|
|
|
const char* entityText = nsnull;
|
|
|
|
|
2000-10-13 11:06:05 +00:00
|
|
|
advanceLength = 0;
|
2000-09-10 22:22:58 +00:00
|
|
|
// for each character in this chunk, check if it
|
|
|
|
// needs to be replaced
|
|
|
|
for (; c < fragmentEnd; c++, advanceLength++) {
|
|
|
|
PRUnichar val = *c;
|
2000-10-13 11:06:05 +00:00
|
|
|
if ((val <= kGTVal) && (entityTable[val][0] != 0)) {
|
|
|
|
entityText = entityTable[val];
|
2000-09-10 22:22:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
aOutputStr.Append(fragmentStart, advanceLength);
|
|
|
|
if (entityText) {
|
2003-11-01 10:57:41 +00:00
|
|
|
AppendASCIItoUTF16(entityText, aOutputStr);
|
2000-09-10 22:22:58 +00:00
|
|
|
advanceLength++;
|
|
|
|
}
|
|
|
|
}
|
2000-10-13 11:06:05 +00:00
|
|
|
|
|
|
|
return;
|
2000-09-10 22:22:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
aOutputStr.Append(aStr);
|
|
|
|
}
|
2002-05-28 12:34:48 +00:00
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsXMLContentSerializer::IsShorthandAttr(const nsIAtom* aAttrName,
|
|
|
|
const nsIAtom* aElementName)
|
|
|
|
{
|
|
|
|
// checked
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::checked) &&
|
|
|
|
(aElementName == nsGkAtoms::input)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// compact
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::compact) &&
|
|
|
|
(aElementName == nsGkAtoms::dir ||
|
|
|
|
aElementName == nsGkAtoms::dl ||
|
|
|
|
aElementName == nsGkAtoms::menu ||
|
|
|
|
aElementName == nsGkAtoms::ol ||
|
|
|
|
aElementName == nsGkAtoms::ul)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// declare
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::declare) &&
|
|
|
|
(aElementName == nsGkAtoms::object)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// defer
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::defer) &&
|
|
|
|
(aElementName == nsGkAtoms::script)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// disabled
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::disabled) &&
|
|
|
|
(aElementName == nsGkAtoms::button ||
|
|
|
|
aElementName == nsGkAtoms::input ||
|
|
|
|
aElementName == nsGkAtoms::optgroup ||
|
|
|
|
aElementName == nsGkAtoms::option ||
|
|
|
|
aElementName == nsGkAtoms::select ||
|
|
|
|
aElementName == nsGkAtoms::textarea)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ismap
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::ismap) &&
|
|
|
|
(aElementName == nsGkAtoms::img ||
|
|
|
|
aElementName == nsGkAtoms::input)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// multiple
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::multiple) &&
|
|
|
|
(aElementName == nsGkAtoms::select)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// noresize
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::noresize) &&
|
|
|
|
(aElementName == nsGkAtoms::frame)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// noshade
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::noshade) &&
|
|
|
|
(aElementName == nsGkAtoms::hr)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// nowrap
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::nowrap) &&
|
|
|
|
(aElementName == nsGkAtoms::td ||
|
|
|
|
aElementName == nsGkAtoms::th)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// readonly
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::readonly) &&
|
|
|
|
(aElementName == nsGkAtoms::input ||
|
|
|
|
aElementName == nsGkAtoms::textarea)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// selected
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aAttrName == nsGkAtoms::selected) &&
|
|
|
|
(aElementName == nsGkAtoms::option)) {
|
2002-05-28 12:34:48 +00:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2002-08-13 18:41:16 +00:00
|
|
|
|
2003-10-23 22:24:21 +00:00
|
|
|
void
|
|
|
|
nsXMLContentSerializer::MaybeAddNewline(nsAString& aStr)
|
|
|
|
{
|
|
|
|
if (mAddNewline) {
|
2008-10-21 20:30:09 +00:00
|
|
|
aStr.Append(mLineBreak);
|
2003-10-23 22:24:21 +00:00
|
|
|
mAddNewline = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXMLContentSerializer::MaybeFlagNewline(nsIDOMNode* aNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
aNode->GetParentNode(getter_AddRefs(parent));
|
|
|
|
if (parent) {
|
|
|
|
PRUint16 type;
|
|
|
|
parent->GetNodeType(&type);
|
|
|
|
mAddNewline = type == nsIDOMNode::DOCUMENT_NODE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-08-13 18:41:16 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXMLContentSerializer::AppendDocumentStart(nsIDOMDocument *aDocument,
|
|
|
|
nsAString& aStr)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aDocument);
|
|
|
|
|
2003-04-19 00:28:09 +00:00
|
|
|
nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDocument));
|
|
|
|
if (!doc) {
|
2002-08-16 23:24:15 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2002-08-13 18:41:16 +00:00
|
|
|
|
|
|
|
nsAutoString version, encoding, standalone;
|
2003-04-19 00:28:09 +00:00
|
|
|
doc->GetXMLDeclaration(version, encoding, standalone);
|
2002-08-13 18:41:16 +00:00
|
|
|
|
|
|
|
if (version.IsEmpty())
|
|
|
|
return NS_OK; // A declaration must have version, or there is no decl
|
|
|
|
|
|
|
|
NS_NAMED_LITERAL_STRING(endQuote, "\"");
|
|
|
|
|
|
|
|
aStr += NS_LITERAL_STRING("<?xml version=\"") + version + endQuote;
|
|
|
|
|
2006-11-28 04:01:46 +00:00
|
|
|
if (!mCharset.IsEmpty()) {
|
|
|
|
aStr += NS_LITERAL_STRING(" encoding=\"") +
|
|
|
|
NS_ConvertASCIItoUTF16(mCharset) + endQuote;
|
2002-08-13 18:41:16 +00:00
|
|
|
}
|
2006-11-28 04:01:46 +00:00
|
|
|
// Otherwise just don't output an encoding attr. Not that we expect
|
|
|
|
// mCharset to ever be empty.
|
|
|
|
#ifdef DEBUG
|
|
|
|
else {
|
|
|
|
NS_WARNING("Empty mCharset? How come?");
|
|
|
|
}
|
|
|
|
#endif
|
2002-08-13 18:41:16 +00:00
|
|
|
|
|
|
|
if (!standalone.IsEmpty()) {
|
|
|
|
aStr += NS_LITERAL_STRING(" standalone=\"") + standalone + endQuote;
|
|
|
|
}
|
|
|
|
|
2004-06-17 00:13:25 +00:00
|
|
|
aStr.AppendLiteral("?>");
|
2003-10-23 22:24:21 +00:00
|
|
|
mAddNewline = PR_TRUE;
|
2002-08-13 18:41:16 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2008-10-21 20:30:09 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
nsXMLContentSerializer::AppendToStringConvertLF(const nsAString& aStr,
|
|
|
|
nsAString& aOutputStr)
|
|
|
|
{
|
|
|
|
// Convert line-endings to mLineBreak
|
|
|
|
PRUint32 start = 0;
|
|
|
|
PRUint32 theLen = aStr.Length();
|
|
|
|
while (start < theLen) {
|
|
|
|
PRInt32 eol = aStr.FindChar('\n', start);
|
|
|
|
if (eol == kNotFound) {
|
|
|
|
nsDependentSubstring dataSubstring(aStr, start, theLen - start);
|
|
|
|
AppendToString(dataSubstring, aOutputStr);
|
|
|
|
start = theLen;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nsDependentSubstring dataSubstring(aStr, start, eol - start);
|
|
|
|
AppendToString(dataSubstring, aOutputStr);
|
|
|
|
AppendToString(mLineBreak, aOutputStr);
|
|
|
|
start = eol + 1;
|
|
|
|
if (start == theLen)
|
|
|
|
mColPos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|