/// <summary> /// Adds a namespace declaration to the declarations currently in scope. /// </summary> /// <param name="ns">The namespace declaration to add.</param> private void _addNamespaceDecl(ASNamespace ns) { // Check if the namespace is declared by an ancestor. for (int i = m_nsInScopePtrs[m_nsInScopePtrs.length - 1] - 1; i >= 0; i--) { ASNamespace parentNs = m_nsInScope[i]; if (parentNs.prefix != ns.prefix) { continue; } if (parentNs.uri == ns.uri) { return; } break; } // Check if there is a duplicate declaration on this node. for (int i = m_nsInScopePtrs[m_nsInScopePtrs.length - 1], n = m_nsInScope.length; i < n; i++) { if (ns.prefix == m_nsInScope[i].prefix) { throw _error(ErrorCode.MARIANA__XML_PARSER_DUPLICATE_NS_DECL); } } m_nsInScope.add(ns); }
/// <summary> /// Creates a new <see cref="ASQName"/> object from a local name. The default namespace will /// be used. /// </summary> /// <param name="localName">The local name of the XML name. This is the name of the XML /// element or attribute without the namespace. If this is the string "*", the QName will /// match XML elements and attributes with any name in any namespace. Otherwise, its namespace /// will be set to the default XML namespace.</param> public ASQName(string?localName) { if (localName != null && localName.Length == 1 && localName[0] == '*') { (uri, prefix) = (null, null); } else { ASNamespace defaultNS = ASNamespace.getDefault(); (uri, prefix) = (defaultNS.uri, defaultNS.prefix); } this.localName = ASString.AS_convertString(localName); }
/// <summary> /// Reads an attribute. /// </summary> private void _readAttribute() { int curLine = m_curLine; if (!_readName(out string?prefix, out string?localName)) { throw _error( ErrorCode.MARIANA__XML_PARSER_INVALID_NAME, (prefix == null) ? localName : prefix + ":" + localName ); } if (m_str.Length - m_pos < 2 || m_str[m_pos] != '=') { throw _error(ErrorCode.XML_PARSER_UNTERMINATED_ATTR); } m_pos++; string attrValue = _readAttributeValue(); if (prefix == null && localName == "xmlns") { _addNamespaceDecl(ASNamespace.unsafeCreate("", attrValue)); } else if (prefix == "xmlns") { if (attrValue.Length == 0) { throw ErrorHelper.createError(ErrorCode.XML_ILLEGAL_PREFIX_PUBLIC_NAMESPACE, localName); } _addNamespaceDecl(ASNamespace.unsafeCreate(localName, attrValue)); } else { // Attribute nodes canot be created at this point; this is because their prefixes // can refer to xmlns declarations after it on the same element tag. So they // must be stored as UnresolvedAttribute until the entire start tag is parsed, // after which their namespace URIs can be resolved and the attribute nodes created. m_unresolvedAttrs.add(new UnresolvedAttribute { lineNumber = curLine, prefix = prefix, localName = localName, value = attrValue, }); } }
/// <summary> /// Checks if the given <see cref="ASQName"/> is a valid node name for an element, attribute /// or processing instruction. If it is not valid, attempts to create a valid name by removing /// the namespace prefix from the name, or by substituting a default namespace URI if the /// name has a null namespace URI. /// </summary> /// /// <param name="name">The <see cref="ASQName"/> instance to check.</param> /// <param name="nodeType">Must be one of <see cref="XMLNodeType.ELEMENT"/>, <see cref="XMLNodeType.ATTRIBUTE"/> /// or <see cref="XMLNodeType.PROCESSING_INSTRUCTION"/>.</param> /// <param name="defaultNS">The default namespace to use if the namespace URI of <paramref name="name"/> /// is null. If this is null, the value of <see cref="ASNamespace.getDefault()"/> is used if /// <paramref name="nodeType"/> if <see cref="XMLNodeType.ELEMENT"/>, and <see cref="ASNamespace.@public"/> /// otherwise.</param> /// /// <returns>If <paramref name="name"/> is a valid name for a node of the given type, returns /// <paramref name="name"/>; if a new valid name could be created by removing the namespace prefix /// and/or by substituting a default namespace URI, returns the new name; otherwise, returns null.</returns> public static ASQName?tryMakeValidNodeName(ASQName?name, XMLNodeType nodeType, ASNamespace?defaultNS = null) { if (name == null || !isValidName(name.localName)) { return(null); } switch (nodeType) { case XMLNodeType.ELEMENT: if (name.uri == null) { return(new ASQName(defaultNS ?? ASNamespace.getDefault(), name.localName)); } break; case XMLNodeType.PROCESSING_INSTRUCTION: if (name.uri == null || name.uri.Length != 0) { return(new ASQName(ASNamespace.@public, name.localName)); } break; case XMLNodeType.ATTRIBUTE: { if (name.uri == null) { name = new ASQName(defaultNS ?? ASNamespace.@public, name.localName); } else if (name.prefix != null && ((name.prefix.Length == 0 && name.uri.Length != 0) || name.prefix == "xmlns")) { name = ASQName.unsafeCreate(prefix: null, name.uri, name.localName); } if (name.uri !.Length == 0 && name.localName == "xmlns") { return(null); } break; } } return(name); }
private void _enterElement(ASXML elem) { _writeIndent(); ASQName elemName = elem.internalGetName() !; var stackItem = new TagStackItem { tempPrefixIdStart = m_nextTempPrefixId, nsDeclBeginIndex = m_nsInScope.length, localName = elemName.localName, prefix = _getPrefix(elemName, isAttr: false) }; elem.internalGetNamespaceDecls(ref m_nsInScope); m_parts.add("<"); _writeName(stackItem.prefix, stackItem.localName); foreach (ASXML attr in elem.getAttributeEnumerator()) { ASQName attrName = attr.internalGetName() !; string attrValue = attr.nodeText !; m_parts.add(" "); _writeName(_getPrefix(attrName, isAttr: true), attrName.localName); m_parts.add("=\""); m_parts.add(XMLHelper.escape(attrValue, 0, attrValue.Length, ref m_escBuffer, isAttr: true)); m_parts.add("\""); } // If this is the root we must include the ancestor namespaces as well. int nsDeclStart = (m_tagStack.length == 0) ? 0 : stackItem.nsDeclBeginIndex; for (int i = nsDeclStart, n = m_nsInScope.length; i < n; i++) { ASNamespace nsDecl = m_nsInScope[i]; if (nsDecl.prefix !.Length != 0) { m_parts.add(" xmlns:"); m_parts.add(nsDecl.prefix); m_parts.add("=\""); }
private void _init(string str) { m_str = str; m_pos = 0; m_curLine = 1; m_defaultNS = ASNamespace.getDefault(); m_parserFlags = 0; var xmlSettings = ASXML.internalSettings; if (xmlSettings.ignoreComments) { m_parserFlags |= FLAG_IGNORE_COMMENTS; } if (xmlSettings.ignoreProcessingInstructions) { m_parserFlags |= FLAG_IGNORE_PI; } if (xmlSettings.ignoreWhitespace) { m_parserFlags |= FLAG_IGNORE_SPACE; } m_nsInScope.clear(); m_nsInScopePtrs.clear(); m_parserStack.clear(); m_nodeStack.clear(); m_unresolvedAttrs.clear(); if (m_buffer == null) { m_buffer = new char[128]; } if (m_namePool == null) { m_namePool = new NamePool(); } }
/// <summary> /// Adds the implicit namespace declarations for the root element for the default /// namespace and the "xml" namespace, if they are used in the document. /// </summary> /// <returns>The namespace declaration array with the implicit declarations added.</returns> /// <param name="rootNSDecls">The namespace declarations to which to add the implicit /// declarations.</param> private ASNamespace[] _addImplicitNSDeclsToRoot(ASNamespace[] rootNSDecls) { int nsDeclSize = rootNSDecls.Length; if ((m_parserFlags & FLAG_USES_XML_NS) != 0) { nsDeclSize++; } if ((m_parserFlags & FLAG_USES_DEFAULT_NS) != 0) { nsDeclSize++; } if (nsDeclSize == rootNSDecls.Length) { return(rootNSDecls); } var newNSDecls = new ASNamespace[nsDeclSize]; int i = 0; for (; i < rootNSDecls.Length; i++) { newNSDecls[i] = rootNSDecls[i]; } if ((m_parserFlags & FLAG_USES_XML_NS) != 0) { newNSDecls[i++] = s_namespaceForXml; } if ((m_parserFlags & FLAG_USES_DEFAULT_NS) != 0) { newNSDecls[i++] = m_defaultNS; } return(newNSDecls); }