/// <summary>The outermost call is special.</summary> /// <remarks> /// The outermost call is special. The names almost certainly differ. The /// qualifiers (and hence options) will differ for an alias to the x-default /// item of a langAlt array. /// </remarks> /// <param name="aliasNode">the alias node</param> /// <param name="baseNode">the base node of the alias</param> /// <param name="outerCall">marks the outer call of the recursion</param> /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards XMP errors</exception> private static void CompareAliasedSubtrees(XMPNode aliasNode, XMPNode baseNode, bool outerCall) { if (!aliasNode.GetValue().Equals(baseNode.GetValue()) || aliasNode.GetChildrenLength() != baseNode.GetChildrenLength()) { throw new XMPException("Mismatch between alias and base nodes", XMPErrorConstants.Badxmp); } if (!outerCall && (!aliasNode.GetName().Equals(baseNode.GetName()) || !aliasNode.GetOptions().Equals(baseNode.GetOptions()) || aliasNode.GetQualifierLength() != baseNode.GetQualifierLength())) { throw new XMPException("Mismatch between alias and base nodes", XMPErrorConstants.Badxmp); } for (Iterator an = aliasNode.IterateChildren(), bn = baseNode.IterateChildren(); an.HasNext() && bn.HasNext();) { XMPNode aliasChild = (XMPNode)an.Next(); XMPNode baseChild = (XMPNode)bn.Next(); CompareAliasedSubtrees(aliasChild, baseChild, false); } for (Iterator an_1 = aliasNode.IterateQualifier(), bn_1 = baseNode.IterateQualifier(); an_1.HasNext() && bn_1.HasNext();) { XMPNode aliasQual = (XMPNode)an_1.Next(); XMPNode baseQual = (XMPNode)bn_1.Next(); CompareAliasedSubtrees(aliasQual, baseQual, false); } }
/// <summary> /// Searches for a qualifier selector in a node: /// [?qualName="value"] - an element in an array, chosen by a qualifier value. /// </summary> /// <remarks> /// Searches for a qualifier selector in a node: /// [?qualName="value"] - an element in an array, chosen by a qualifier value. /// No implicit nodes are created for qualifier selectors, /// except for an alias to an x-default item. /// </remarks> /// <param name="arrayNode">an array node</param> /// <param name="qualName">the qualifier name</param> /// <param name="qualValue">the qualifier value</param> /// <param name="aliasForm"> /// in case the qual selector results from an alias, /// an x-default node is created if there has not been one. /// </param> /// <returns>Returns the index of th</returns> /// <exception cref="Com.Adobe.Xmp.XMPException"></exception> private static int LookupQualSelector(XMPNode arrayNode, string qualName, string qualValue, int aliasForm) { if (XMPConstConstants.XmlLang.Equals(qualName)) { qualValue = Utils.NormalizeLangValue(qualValue); int index = Com.Adobe.Xmp.Impl.XMPNodeUtils.LookupLanguageItem(arrayNode, qualValue); if (index < 0 && (aliasForm & AliasOptions.PropArrayAltText) > 0) { XMPNode langNode = new XMPNode(XMPConstConstants.ArrayItemName, null); XMPNode xdefault = new XMPNode(XMPConstConstants.XmlLang, XMPConstConstants.XDefault, null); langNode.AddQualifier(xdefault); arrayNode.AddChild(1, langNode); return(1); } else { return(index); } } else { for (int index = 1; index < arrayNode.GetChildrenLength(); index++) { XMPNode currItem = arrayNode.GetChild(index); for (Iterator it = currItem.IterateQualifier(); it.HasNext();) { XMPNode qualifier = (XMPNode)it.Next(); if (qualName.Equals(qualifier.GetName()) && qualValue.Equals(qualifier.GetValue())) { return(index); } } } return(-1); } }
/// <summary>The outermost call is special.</summary> /// <remarks> /// The outermost call is special. The names almost certainly differ. The /// qualifiers (and hence options) will differ for an alias to the x-default /// item of a langAlt array. /// </remarks> /// <param name="aliasNode">the alias node</param> /// <param name="baseNode">the base node of the alias</param> /// <param name="outerCall">marks the outer call of the recursion</param> /// <exception cref="Com.Adobe.Xmp.XMPException">Forwards XMP errors</exception> private static void CompareAliasedSubtrees(XMPNode aliasNode, XMPNode baseNode, bool outerCall) { if (!aliasNode.GetValue().Equals(baseNode.GetValue()) || aliasNode.GetChildrenLength() != baseNode.GetChildrenLength()) { throw new XMPException("Mismatch between alias and base nodes", XMPErrorConstants.Badxmp); } if (!outerCall && (!aliasNode.GetName().Equals(baseNode.GetName()) || !aliasNode.GetOptions().Equals(baseNode.GetOptions()) || aliasNode.GetQualifierLength() != baseNode.GetQualifierLength())) { throw new XMPException("Mismatch between alias and base nodes", XMPErrorConstants.Badxmp); } for (Iterator an = aliasNode.IterateChildren(), bn = baseNode.IterateChildren(); an.HasNext() && bn.HasNext(); ) { XMPNode aliasChild = (XMPNode)an.Next(); XMPNode baseChild = (XMPNode)bn.Next(); CompareAliasedSubtrees(aliasChild, baseChild, false); } for (Iterator an_1 = aliasNode.IterateQualifier(), bn_1 = baseNode.IterateQualifier(); an_1.HasNext() && bn_1.HasNext(); ) { XMPNode aliasQual = (XMPNode)an_1.Next(); XMPNode baseQual = (XMPNode)bn_1.Next(); CompareAliasedSubtrees(aliasQual, baseQual, false); } }
/// <summary>Recursively handles the "value" for a node.</summary> /// <remarks> /// Recursively handles the "value" for a node. It does not matter if it is a /// top level property, a field of a struct, or an item of an array. The /// indent is that for the property element. An xml:lang qualifier is written /// as an attribute of the property start tag, not by itself forcing the /// qualified property form. The patterns below mostly ignore attribute /// qualifiers like xml:lang. Except for the one struct case, attribute /// qualifiers don't affect the output form. /// <blockquote> /// <pre> /// <ns:UnqualifiedSimpleProperty>value</ns:UnqualifiedSimpleProperty> /// <ns:UnqualifiedStructProperty> (If no rdf:resource qualifier) /// <rdf:Description> /// ... Fields, same forms as top level properties /// </rdf:Description> /// </ns:UnqualifiedStructProperty> /// <ns:ResourceStructProperty rdf:resource="URI" /// ... Fields as attributes /// > /// <ns:UnqualifiedArrayProperty> /// <rdf:Bag> or Seq or Alt /// ... Array items as rdf:li elements, same forms as top level properties /// </rdf:Bag> /// </ns:UnqualifiedArrayProperty> /// <ns:QualifiedProperty> /// <rdf:Description> /// <rdf:value> ... Property "value" following the unqualified /// forms ... </rdf:value> /// ... Qualifiers looking like named struct fields /// </rdf:Description> /// </ns:QualifiedProperty> /// </pre> /// </blockquote> /// </remarks> /// <param name="node">the property node</param> /// <param name="emitAsRDFValue">property shall be rendered as attribute rather than tag</param> /// <param name="useCanonicalRDF"> /// use canonical form with inner description tag or /// the compact form with rdf:ParseType="resource" attribute. /// </param> /// <param name="indent">the current indent level</param> /// <exception cref="System.IO.IOException">Forwards all writer exceptions.</exception> /// <exception cref="Com.Adobe.Xmp.XMPException">If "rdf:resource" and general qualifiers are mixed.</exception> private void SerializeCanonicalRDFProperty(XMPNode node, bool useCanonicalRDF, bool emitAsRDFValue, int indent) { bool emitEndTag = true; bool indentEndTag = true; // Determine the XML element name. Open the start tag with the name and // attribute qualifiers. string elemName = node.GetName(); if (emitAsRDFValue) { elemName = "rdf:value"; } else { if (XMPConstConstants.ArrayItemName.Equals(elemName)) { elemName = "rdf:li"; } } WriteIndent(indent); Write('<'); Write(elemName); bool hasGeneralQualifiers = false; bool hasRDFResourceQual = false; for (Iterator it = node.IterateQualifier(); it.HasNext(); ) { XMPNode qualifier = (XMPNode)it.Next(); if (!RdfAttrQualifier.Contains(qualifier.GetName())) { hasGeneralQualifiers = true; } else { hasRDFResourceQual = "rdf:resource".Equals(qualifier.GetName()); if (!emitAsRDFValue) { Write(' '); Write(qualifier.GetName()); Write("=\""); AppendNodeValue(qualifier.GetValue(), true); Write('"'); } } } // Process the property according to the standard patterns. if (hasGeneralQualifiers && !emitAsRDFValue) { // This node has general, non-attribute, qualifiers. Emit using the // qualified property form. // ! The value is output by a recursive call ON THE SAME NODE with // emitAsRDFValue set. if (hasRDFResourceQual) { throw new XMPException("Can't mix rdf:resource and general qualifiers", XMPErrorConstants.Badrdf); } // Change serialization to canonical format with inner rdf:Description-tag // depending on option if (useCanonicalRDF) { Write(">"); WriteNewline(); indent++; WriteIndent(indent); Write(RdfStructStart); Write(">"); } else { Write(" rdf:parseType=\"Resource\">"); } WriteNewline(); SerializeCanonicalRDFProperty(node, useCanonicalRDF, true, indent + 1); for (Iterator it_1 = node.IterateQualifier(); it_1.HasNext(); ) { XMPNode qualifier = (XMPNode)it_1.Next(); if (!RdfAttrQualifier.Contains(qualifier.GetName())) { SerializeCanonicalRDFProperty(qualifier, useCanonicalRDF, false, indent + 1); } } if (useCanonicalRDF) { WriteIndent(indent); Write(RdfStructEnd); WriteNewline(); indent--; } } else { // This node has no general qualifiers. Emit using an unqualified form. if (!node.GetOptions().IsCompositeProperty()) { // This is a simple property. if (node.GetOptions().IsURI()) { Write(" rdf:resource=\""); AppendNodeValue(node.GetValue(), true); Write("\"/>"); WriteNewline(); emitEndTag = false; } else { if (node.GetValue() == null || string.Empty.Equals(node.GetValue())) { Write("/>"); WriteNewline(); emitEndTag = false; } else { Write('>'); AppendNodeValue(node.GetValue(), false); indentEndTag = false; } } } else { if (node.GetOptions().IsArray()) { // This is an array. Write('>'); WriteNewline(); EmitRDFArrayTag(node, true, indent + 1); if (node.GetOptions().IsArrayAltText()) { XMPNodeUtils.NormalizeLangArray(node); } for (Iterator it_1 = node.IterateChildren(); it_1.HasNext(); ) { XMPNode child = (XMPNode)it_1.Next(); SerializeCanonicalRDFProperty(child, useCanonicalRDF, false, indent + 2); } EmitRDFArrayTag(node, false, indent + 1); } else { if (!hasRDFResourceQual) { // This is a "normal" struct, use the rdf:parseType="Resource" form. if (!node.HasChildren()) { // Change serialization to canonical format with inner rdf:Description-tag // if option is set if (useCanonicalRDF) { Write(">"); WriteNewline(); WriteIndent(indent + 1); Write(RdfEmptyStruct); } else { Write(" rdf:parseType=\"Resource\"/>"); emitEndTag = false; } WriteNewline(); } else { // Change serialization to canonical format with inner rdf:Description-tag // if option is set if (useCanonicalRDF) { Write(">"); WriteNewline(); indent++; WriteIndent(indent); Write(RdfStructStart); Write(">"); } else { Write(" rdf:parseType=\"Resource\">"); } WriteNewline(); for (Iterator it_1 = node.IterateChildren(); it_1.HasNext(); ) { XMPNode child = (XMPNode)it_1.Next(); SerializeCanonicalRDFProperty(child, useCanonicalRDF, false, indent + 1); } if (useCanonicalRDF) { WriteIndent(indent); Write(RdfStructEnd); WriteNewline(); indent--; } } } else { // This is a struct with an rdf:resource attribute, use the // "empty property element" form. for (Iterator it_1 = node.IterateChildren(); it_1.HasNext(); ) { XMPNode child = (XMPNode)it_1.Next(); if (!CanBeRDFAttrProp(child)) { throw new XMPException("Can't mix rdf:resource and complex fields", XMPErrorConstants.Badrdf); } WriteNewline(); WriteIndent(indent + 1); Write(' '); Write(child.GetName()); Write("=\""); AppendNodeValue(child.GetValue(), true); Write('"'); } Write("/>"); WriteNewline(); emitEndTag = false; } } } } // Emit the property element end tag. if (emitEndTag) { if (indentEndTag) { WriteIndent(indent); } Write("</"); Write(elemName); Write('>'); WriteNewline(); } }
/// <summary>Writes all used namespaces of the subtree in node to the output.</summary> /// <remarks> /// Writes all used namespaces of the subtree in node to the output. /// The subtree is recursivly traversed. /// </remarks> /// <param name="node">the root node of the subtree</param> /// <param name="usedPrefixes">a set containing currently used prefixes</param> /// <param name="indent">the current indent level</param> /// <exception cref="System.IO.IOException">Forwards all writer exceptions.</exception> private void DeclareUsedNamespaces(XMPNode node, HashSet<string> usedPrefixes, int indent) { if (node.GetOptions().IsSchemaNode()) { // The schema node name is the URI, the value is the prefix. string prefix = Sharpen.Runtime.Substring(node.GetValue(), 0, node.GetValue().Length - 1); DeclareNamespace(prefix, node.GetName(), usedPrefixes, indent); } else { if (node.GetOptions().IsStruct()) { for (Iterator it = node.IterateChildren(); it.HasNext(); ) { XMPNode field = (XMPNode)it.Next(); DeclareNamespace(field.GetName(), null, usedPrefixes, indent); } } } for (Iterator it_1 = node.IterateChildren(); it_1.HasNext(); ) { XMPNode child = (XMPNode)it_1.Next(); DeclareUsedNamespaces(child, usedPrefixes, indent); } for (Iterator it_2 = node.IterateQualifier(); it_2.HasNext(); ) { XMPNode qualifier = (XMPNode)it_2.Next(); DeclareNamespace(qualifier.GetName(), null, usedPrefixes, indent); DeclareUsedNamespaces(qualifier, usedPrefixes, indent); } }
/// <summary>Serializes the general qualifier.</summary> /// <param name="node">the root node of the subtree</param> /// <param name="indent">the current indent level</param> /// <exception cref="System.IO.IOException">Forwards all writer exceptions.</exception> /// <exception cref="Com.Adobe.Xmp.XMPException">If qualifier and element fields are mixed.</exception> private void SerializeCompactRDFGeneralQualifier(int indent, XMPNode node) { // The node has general qualifiers, ones that can't be // attributes on a property element. // Emit using the qualified property pseudo-struct form. The // value is output by a call // to SerializePrettyRDFProperty with emitAsRDFValue set. Write(" rdf:parseType=\"Resource\">"); WriteNewline(); SerializeCanonicalRDFProperty(node, false, true, indent + 1); for (Iterator iq = node.IterateQualifier(); iq.HasNext(); ) { XMPNode qualifier = (XMPNode)iq.Next(); SerializeCanonicalRDFProperty(qualifier, false, false, indent + 1); } }