/// <summary>
        /// Writes the context attributes.
        /// </summary>
        /// <param name="writer">The writer.</param>
        /// <param name="data">The data.</param>
        protected virtual void WriteContextAttributes(XmlWriter writer, XacmlContextAttributes data) {
            Contract.Requires<ArgumentNullException>(writer != null);
            Contract.Requires<ArgumentNullException>(data != null);

            writer.WriteStartElement(XacmlConstants.Prefixes.Context, XacmlConstants.ElementNames.Attributes, this.version.NamespacePolicy);
            writer.WriteAttributeString(XacmlConstants.AttributeNames.Category, data.Category.OriginalString);

            if (data.Id != null) {
                writer.WriteAttributeString(XacmlConstants.Prefixes.Xml, XacmlConstants.AttributeNames.Id, XacmlConstants.Namespaces.XmlNamespace, data.Id.ToString());
            }

            if (!string.IsNullOrEmpty(data.Content)) {
                writer.WriteElementString(XacmlConstants.Prefixes.Context, XacmlConstants.ElementNames.Content, this.version.NamespacePolicy, data.Content);
            }

            foreach (var attr in data.Attributes) {
                writer.WriteStartElement(XacmlConstants.Prefixes.Context, XacmlConstants.ElementNames.Attribute, this.version.NamespacePolicy);

                writer.WriteAttributeString(XacmlConstants.AttributeNames.AttributeId, attr.AttributeId.OriginalString);
                writer.WriteAttributeString(XacmlConstants.AttributeNames.IncludeInResult, attr.IncludeInResult.ToString());

                if (!string.IsNullOrEmpty(attr.Issuer)) {
                    writer.WriteAttributeString(XacmlConstants.AttributeNames.Issuer, attr.Issuer);
                }

                foreach (XacmlAttributeValue attrVal in attr.AttributeValues) {
                    this.WriteAttributeValue(writer, attrVal);
                }

                writer.WriteEndElement();
            }

            writer.WriteEndElement();
        }
        /// <summary>
        /// Reads the context attributes.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <returns></returns>
        protected virtual XacmlContextAttributes ReadContextAttributes(XmlReader reader) {
            Contract.Requires<ArgumentNullException>(reader != null, "reader");
            Contract.Requires<XmlException>(reader.IsStartElement(XacmlConstants.ElementNames.Attributes, this.version.NamespaceContext));

            Uri category = this.ReadAttribute<Uri>(reader, XacmlConstants.AttributeNames.Category);
            string id = this.ReadAttribute<string>(reader, XacmlConstants.AttributeNames.Id, namespaceURI: XacmlConstants.Namespaces.XmlNamespace, isRequered: false);

            var result = new XacmlContextAttributes(category) { Id = id };

            if (reader.IsEmptyElement) {
                reader.Read();
                return result;
            }

            reader.ReadStartElement(XacmlConstants.ElementNames.Attributes, this.version.NamespacePolicy);

            if (reader.IsStartElement(XacmlConstants.ElementNames.Content, this.version.NamespacePolicy)) {
                result.Content = reader.ReadInnerXml();
            }

            this.ReadList<XacmlAttribute>(result.Attributes, XacmlConstants.ElementNames.Attribute, this.version.NamespacePolicy, ReadAttribute, reader, false);

            reader.ReadEndElement();

            return result;
        }