// c14n parameters
private bool comments;
private bool exclusive;
+ string inclusiveNamespacesPrefixList;
// input/output
private XmlNodeList xnl;
private ArrayList visibleNamespaces;
private int prevVisibleNamespacesStart;
private int prevVisibleNamespacesEnd;
+ private Hashtable propagatedNss;
- public XmlCanonicalizer (bool withComments, bool excC14N)
+ public XmlCanonicalizer (bool withComments, bool excC14N, Hashtable propagatedNamespaces)
{
res = new StringBuilder ();
comments = withComments;
exclusive = excC14N;
+ propagatedNss = propagatedNamespaces;
+ }
+
+ void Initialize ()
+ {
state = XmlCanonicalizerState.BeforeDocElement;
visibleNamespaces = new ArrayList ();
prevVisibleNamespacesStart = 0;
prevVisibleNamespacesEnd = 0;
+ res.Length = 0;
}
public Stream Canonicalize (XmlDocument doc)
{
+ if (doc == null)
+ throw new ArgumentNullException ("doc");
+ Initialize ();
+
+ FillMissingPrefixes (doc, new XmlNamespaceManager (doc.NameTable), new ArrayList ());
WriteDocumentNode (doc);
UTF8Encoding utf8 = new UTF8Encoding ();
xnl = nodes;
if (nodes == null || nodes.Count < 1)
return new MemoryStream ();
- return Canonicalize (nodes[0].OwnerDocument);
+ XmlNode n = nodes [0];
+ return Canonicalize (n.NodeType == XmlNodeType.Document ? n as XmlDocument : n.OwnerDocument);
}
+ // See xml-enc-c14n specification
+ public string InclusiveNamespacesPrefixList {
+ get { return inclusiveNamespacesPrefixList; }
+ set { inclusiveNamespacesPrefixList = value; }
+ }
+
+ XmlAttribute CreateXmlns (XmlNode n)
+ {
+ XmlAttribute a = n.Prefix.Length == 0 ?
+ n.OwnerDocument.CreateAttribute ("xmlns", "http://www.w3.org/2000/xmlns/") :
+ n.OwnerDocument.CreateAttribute ("xmlns", n.Prefix, "http://www.w3.org/2000/xmlns/");
+ a.Value = n.NamespaceURI;
+ return a;
+ }
+
+ // Note that this must be done *before* filtering nodes out
+ // by context node list.
+ private void FillMissingPrefixes (XmlNode n, XmlNamespaceManager nsmgr, ArrayList tmpList)
+ {
+ if (n.Prefix.Length == 0 && propagatedNss != null) {
+ foreach (DictionaryEntry de in propagatedNss)
+ if ((string) de.Value == n.NamespaceURI) {
+ n.Prefix = (string) de.Key;
+ break;
+ }
+ }
+
+ if (n.NodeType == XmlNodeType.Element && ((XmlElement) n).HasAttributes) {
+ foreach (XmlAttribute a in n.Attributes)
+ if (a.NamespaceURI == "http://www.w3.org/2000/xmlns/")
+ nsmgr.AddNamespace (a.Prefix.Length == 0 ? String.Empty : a.LocalName, a.Value);
+ nsmgr.PushScope ();
+ }
+
+ if (n.NamespaceURI.Length > 0 && nsmgr.LookupPrefix (n.NamespaceURI) == null)
+ tmpList.Add (CreateXmlns (n));
+
+ if (n.NodeType == XmlNodeType.Element && ((XmlElement) n).HasAttributes) {
+ foreach (XmlAttribute a in n.Attributes)
+ if (a.NamespaceURI.Length > 0 && nsmgr.LookupNamespace (a.Prefix) == null)
+ tmpList.Add (CreateXmlns (a));
+ }
+
+ foreach (XmlAttribute a in tmpList)
+ ((XmlElement) n).SetAttributeNode (a);
+ tmpList.Clear ();
+
+ if (n.HasChildNodes) {
+ for (XmlNode c = n.FirstChild; c != null; c = c.NextSibling)
+ if (c.NodeType == XmlNodeType.Element)
+ FillMissingPrefixes (c, nsmgr, tmpList);
+ }
+ nsmgr.PopScope ();
+ }
+
private void WriteNode (XmlNode node)
{
// Console.WriteLine ("C14N Debug: node=" + node.Name);
bool has_empty_namespace = false;
ArrayList list = new ArrayList ();
for (XmlNode cur = node; cur != null && cur != doc; cur = cur.ParentNode) {
- foreach (XmlNode attribute in cur.Attributes) {
+ foreach (XmlAttribute attribute in cur.Attributes) {
if (!IsNamespaceNode (attribute))
continue;
// check that we have not rendered it yet
bool rendered = IsNamespaceRendered (prefix, attribute.Value);
+ // For exc-c14n, only visibly utilized
+ // namespaces are written.
+ if (exclusive && !IsVisiblyUtilized (node as XmlElement, attribute))
+ continue;
+
// add to the visible namespaces stack
if (visible)
visibleNamespaces.Add (attribute);
}
}
- // add empty namespace if needed
- if (visible && !has_empty_namespace && !IsNamespaceRendered (string.Empty, string.Empty))
+ // add empty namespace if needed
+ if (visible && !has_empty_namespace && !IsNamespaceRendered (string.Empty, string.Empty) && node.NamespaceURI == String.Empty)
res.Append (" xmlns=\"\"");
list.Sort (new XmlDsigC14NTransformNamespacesComparer ());
res.Append ("?>");
}
}
-
+
+ // determines whether the node is in the node-set or not.
private bool IsNodeVisible (XmlNode node)
{
// if node list is empty then we process whole document
return false;
}
+
+ // This method assumes that the namespace node is *not*
+ // rendered yet.
+ private bool IsVisiblyUtilized (XmlElement owner, XmlAttribute ns)
+ {
+ if (owner == null)
+ return false;
+
+ string prefix = ns.LocalName == "xmlns" ? String.Empty : ns.LocalName;
+ if (owner.Prefix == prefix && owner.NamespaceURI == ns.Value)
+ return true;
+ if (!owner.HasAttributes)
+ return false;
+ foreach (XmlAttribute a in owner.Attributes) {
+ if (a.Prefix == String.Empty)
+ continue;
+ if (a.Prefix != prefix || a.NamespaceURI != ns.Value)
+ continue;
+ if (IsNodeVisible (a))
+ return true;
+ }
+ return false;
+ }
private bool IsNamespaceRendered (string prefix, string uri)
{
else if (n2 == null)
return 1;
else if (n1.Prefix == n2.Prefix)
- return string.Compare (n1.LocalName, n2.LocalName);
+ return string.CompareOrdinal (n1.LocalName, n2.LocalName);
// Attributes in the default namespace are first
// because the default namespace is not applied to