|
|
@@ -38,6 +38,12 @@ using System.Globalization;
|
|
|
using System.Xml;
|
|
|
using System.Xml.Schema;
|
|
|
|
|
|
+#if NET_2_0
|
|
|
+using NSResolver = System.Xml.IXmlNamespaceResolver;
|
|
|
+#else
|
|
|
+using NSResolver = System.Xml.XmlNamespaceManager;
|
|
|
+#endif
|
|
|
+
|
|
|
namespace Mono.Xml.Schema
|
|
|
{
|
|
|
internal class XsdKeyEntryField
|
|
|
@@ -86,9 +92,9 @@ namespace Mono.Xml.Schema
|
|
|
FieldLinePosition = li.LinePosition;
|
|
|
}
|
|
|
|
|
|
- if (!(this.entry.KeySequence.SourceSchemaIdentity is XmlSchemaKeyref)) {
|
|
|
- for (int i = 0; i < entry.KeySequence.FinishedEntries.Count; i++) {
|
|
|
- XsdKeyEntry other = (XsdKeyEntry) entry.KeySequence.FinishedEntries [i];
|
|
|
+ if (!(this.entry.OwnerSequence.SourceSchemaIdentity is XmlSchemaKeyref)) {
|
|
|
+ for (int i = 0; i < entry.OwnerSequence.FinishedEntries.Count; i++) {
|
|
|
+ XsdKeyEntry other = (XsdKeyEntry) entry.OwnerSequence.FinishedEntries [i];
|
|
|
if (this.entry.CompareIdentity (other))
|
|
|
return false;
|
|
|
}
|
|
|
@@ -97,44 +103,59 @@ namespace Mono.Xml.Schema
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- // It might throw Exception including other than XmlSchemaException (ReadTypedValue).
|
|
|
- internal XsdIdentityPath FieldMatches (ArrayList qnameStack, XsdValidatingReader reader)
|
|
|
+ // if (elementPath) check only elements; else only attributes.
|
|
|
+ internal XsdIdentityPath Matches (bool matchesAttr, object sender, XmlNameTable nameTable, ArrayList qnameStack, string sourceUri, object schemaType, NSResolver nsResolver, IXmlLineInfo lineInfo, int depth, string attrName, string attrNS, string attrValue)
|
|
|
{
|
|
|
for (int i = 0; i < field.Paths.Length; i++) {
|
|
|
XsdIdentityPath path = field.Paths [i];
|
|
|
- if (FieldFound && (reader.Depth > this.FieldFoundDepth && this.FieldFoundPath == path))
|
|
|
+ bool isAttribute = path.IsAttribute;
|
|
|
+ if (matchesAttr != isAttribute)
|
|
|
+ continue;
|
|
|
+ XsdIdentityStep step;
|
|
|
+ if (path.IsAttribute) {
|
|
|
+ step = path.OrderedSteps [path.OrderedSteps.Length - 1];
|
|
|
+ bool match = false;
|
|
|
+ if (step.IsAnyName || step.NsName != null) {
|
|
|
+ if (step.IsAnyName || attrNS == step.NsName)
|
|
|
+ match = true;
|
|
|
+ }
|
|
|
+ else if (step.Name == attrName && step.Namespace == attrNS)
|
|
|
+ match = true;
|
|
|
+ if (match) {
|
|
|
+ this.FillAttributeFieldValue (sender, nameTable, sourceUri, schemaType, nsResolver, attrValue, lineInfo, depth);
|
|
|
+ if (this.Identity != null)
|
|
|
+ return path;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (FieldFound && (depth > this.FieldFoundDepth && this.FieldFoundPath == path))
|
|
|
continue;
|
|
|
|
|
|
// Only "." hits.
|
|
|
if (path.OrderedSteps.Length == 0) {
|
|
|
- if (reader.Depth == entry.StartDepth)
|
|
|
+ if (depth == entry.StartDepth)
|
|
|
return path;
|
|
|
else
|
|
|
continue;
|
|
|
}
|
|
|
// It does not hit as yet (too shallow to hit).
|
|
|
- if (reader.Depth - entry.StartDepth < path.OrderedSteps.Length - 1)
|
|
|
+ if (depth - entry.StartDepth < path.OrderedSteps.Length - 1)
|
|
|
continue;
|
|
|
|
|
|
- bool isAttributePath = false;
|
|
|
int iter = path.OrderedSteps.Length;
|
|
|
- if (path.OrderedSteps [iter-1].IsAttribute) {
|
|
|
- isAttributePath = true;
|
|
|
+ if (isAttribute)
|
|
|
iter--;
|
|
|
- }
|
|
|
- if (path.Descendants && reader.Depth < entry.StartDepth + iter)
|
|
|
+ if (path.Descendants && depth < entry.StartDepth + iter)
|
|
|
continue;
|
|
|
- else if (!path.Descendants && reader.Depth != entry.StartDepth + iter)
|
|
|
+ else if (!path.Descendants && depth != entry.StartDepth + iter)
|
|
|
continue;
|
|
|
|
|
|
iter--;
|
|
|
|
|
|
- XsdIdentityStep step;
|
|
|
for (; iter >= 0; iter--) {
|
|
|
step = path.OrderedSteps [iter];
|
|
|
- if (step.IsAnyName)
|
|
|
+ if (step.IsCurrent || step.IsAnyName)
|
|
|
continue;
|
|
|
- XmlQualifiedName qname = (XmlQualifiedName) qnameStack [entry.StartDepth + iter + 1];
|
|
|
+ XmlQualifiedName qname = (XmlQualifiedName) qnameStack [entry.StartDepth + iter + (isAttribute ? 0 : 1)];
|
|
|
if (step.NsName != null && qname.Namespace == step.NsName)
|
|
|
continue;
|
|
|
if ((step.Name == "*" || step.Name == qname.Name) &&
|
|
|
@@ -145,152 +166,54 @@ namespace Mono.Xml.Schema
|
|
|
}
|
|
|
if (iter >= 0) // i.e. did not match against the path.
|
|
|
continue;
|
|
|
- if (!isAttributePath)
|
|
|
- return path;
|
|
|
- step = path.OrderedSteps [path.OrderedSteps.Length - 1];
|
|
|
- if (step.IsAnyName || step.NsName != null) {
|
|
|
- try {
|
|
|
- while (reader.MoveToNextAttribute ()) {
|
|
|
- if (reader.NamespaceURI == XmlSchema.InstanceNamespace)
|
|
|
- continue;
|
|
|
- if (step.IsAnyName || reader.NamespaceURI == step.NsName) {
|
|
|
- this.FillAttributeFieldValue (reader);
|
|
|
- }
|
|
|
- }
|
|
|
- } finally {
|
|
|
- reader.MoveToElement ();
|
|
|
- }
|
|
|
- if (this.Identity != null)
|
|
|
- return path;
|
|
|
- else
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (reader.MoveToAttribute (step.Name, step.Namespace)) {
|
|
|
- this.FillAttributeFieldValue (reader);
|
|
|
- reader.MoveToElement ();
|
|
|
- return path;
|
|
|
- }
|
|
|
- else
|
|
|
- continue;
|
|
|
+
|
|
|
+ return path;
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- private void FillAttributeFieldValue (XsdValidatingReader reader)
|
|
|
+ private void FillAttributeFieldValue (object sender, XmlNameTable nameTable, string sourceUri, object schemaType, NSResolver nsResolver, string value, IXmlLineInfo lineInfo, int depth)
|
|
|
{
|
|
|
if (this.FieldFound)
|
|
|
- throw new XmlSchemaException ("The key value was was already found."
|
|
|
+ throw new XmlSchemaException ("The key value was already found."
|
|
|
+ (this.FieldHasLineInfo ?
|
|
|
String.Format (CultureInfo.InvariantCulture, " At line {0}, position {1}.", FieldLineNumber, FieldLinePosition) :
|
|
|
""),
|
|
|
- reader, reader.BaseURI, entry.KeySequence.SourceSchemaIdentity, null);
|
|
|
- XmlSchemaDatatype dt = reader.SchemaType as XmlSchemaDatatype;
|
|
|
- XmlSchemaSimpleType st = reader.SchemaType as XmlSchemaSimpleType;
|
|
|
+ sender, sourceUri, entry.OwnerSequence.SourceSchemaIdentity, null);
|
|
|
+ XmlSchemaDatatype dt = schemaType as XmlSchemaDatatype;
|
|
|
+ XmlSchemaSimpleType st = schemaType as XmlSchemaSimpleType;
|
|
|
if (dt == null && st != null)
|
|
|
dt = st.Datatype;
|
|
|
- object identity = XmlSchemaUtil.ReadTypedValue (reader, reader.SchemaType, reader.ParserContext.NamespaceManager, null);
|
|
|
- if (identity == null)
|
|
|
- identity = reader.Value;
|
|
|
- if (!this.SetIdentityField (identity, reader.Depth - 1 == reader.XsiNilDepth , dt as XsdAnySimpleType, reader.Depth, (IXmlLineInfo) reader))
|
|
|
- throw new XmlSchemaException ("Two or more identical field was found.",
|
|
|
- reader, reader.BaseURI, entry.KeySequence.SourceSchemaIdentity, null);
|
|
|
- // HACK: This is not logical. Attributes never be cosuming,
|
|
|
- // so I used it as a temporary mark to sign it is *just* validated now.
|
|
|
- this.Consuming = true;
|
|
|
- this.FieldFound = true;
|
|
|
+ object identity = null;
|
|
|
+ try {
|
|
|
+ if (dt != null)
|
|
|
+ identity = dt.ParseValue (value, nameTable, nsResolver);
|
|
|
+ if (identity == null)
|
|
|
+ identity = value;
|
|
|
+ if (!this.SetIdentityField (identity, false, dt as XsdAnySimpleType, depth, lineInfo))
|
|
|
+ throw new XmlSchemaException ("Two or more identical field was found.",
|
|
|
+ sender, sourceUri, entry.OwnerSequence.SourceSchemaIdentity, null);
|
|
|
+ // HACK: This is not logical. Attributes never be cosuming,
|
|
|
+ // so I used it as a temporary mark to sign it is *just* validated now.
|
|
|
+ this.Consuming = true;
|
|
|
+ this.FieldFound = true;
|
|
|
+ } catch (Exception ex) {
|
|
|
+ throw new XmlSchemaException ("Failed to read typed value.", sender, sourceUri, entry.OwnerSequence.SourceSchemaIdentity, ex);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- internal class XsdKeyEntryFieldCollection : IList
|
|
|
+ internal class XsdKeyEntryFieldCollection : CollectionBase
|
|
|
{
|
|
|
- ArrayList al = new ArrayList ();
|
|
|
-
|
|
|
- #region IList
|
|
|
- public bool IsReadOnly {
|
|
|
- get { return false; }
|
|
|
- }
|
|
|
-
|
|
|
- object IList.this [int i] {
|
|
|
- get { return al [i]; }
|
|
|
- set { al [i] = value; }
|
|
|
- }
|
|
|
-
|
|
|
public XsdKeyEntryField this [int i] {
|
|
|
- get { return (XsdKeyEntryField) al [i]; }
|
|
|
- set { al [i] = value; }
|
|
|
- }
|
|
|
-
|
|
|
- public void RemoveAt (int i)
|
|
|
- {
|
|
|
- al.RemoveAt (i);
|
|
|
- }
|
|
|
-
|
|
|
- public void Insert (int i, object value)
|
|
|
- {
|
|
|
- al.Insert (i, value);
|
|
|
- }
|
|
|
-
|
|
|
- public void Remove (object value)
|
|
|
- {
|
|
|
- al.Remove (value);
|
|
|
- }
|
|
|
-
|
|
|
- public bool Contains (object value)
|
|
|
- {
|
|
|
- return al.Contains (value);
|
|
|
- }
|
|
|
-
|
|
|
- public void Clear ()
|
|
|
- {
|
|
|
- al.Clear ();
|
|
|
+ get { return (XsdKeyEntryField) List [i]; }
|
|
|
+ set { List [i] = value; }
|
|
|
}
|
|
|
|
|
|
- public int IndexOf (object value)
|
|
|
+ public int Add (XsdKeyEntryField value)
|
|
|
{
|
|
|
- return al.IndexOf (value);
|
|
|
+ return List.Add (value);
|
|
|
}
|
|
|
-
|
|
|
- public int Add (object value)
|
|
|
- {
|
|
|
- return al.Add (value);
|
|
|
- }
|
|
|
-
|
|
|
- public bool IsFixedSize {
|
|
|
- get { return false; }
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region ICollection
|
|
|
-
|
|
|
- public bool IsSynchronized {
|
|
|
- get { return al.IsSynchronized; }
|
|
|
- }
|
|
|
-
|
|
|
- public int Count {
|
|
|
- get { return al.Count; }
|
|
|
- }
|
|
|
-
|
|
|
- public void CopyTo(Array array, int i)
|
|
|
- {
|
|
|
- al.CopyTo (array, i);
|
|
|
- }
|
|
|
-
|
|
|
- public object SyncRoot {
|
|
|
- get { return al.SyncRoot; }
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
- #region IEnumerable
|
|
|
-
|
|
|
- public IEnumerator GetEnumerator ()
|
|
|
- {
|
|
|
- return ((IEnumerable) al).GetEnumerator ();
|
|
|
- }
|
|
|
-
|
|
|
- #endregion
|
|
|
-
|
|
|
}
|
|
|
|
|
|
// Created per field/key pair, created per selector-matched element.
|
|
|
@@ -311,7 +234,7 @@ namespace Mono.Xml.Schema
|
|
|
// public int KeyRefSelectorLinePosition;
|
|
|
// public bool KeyRefSelectorHasLineInfo;
|
|
|
|
|
|
- public XsdKeyTable KeySequence;
|
|
|
+ public XsdKeyTable OwnerSequence;
|
|
|
private bool keyFound = false;
|
|
|
|
|
|
public XsdKeyEntry (
|
|
|
@@ -337,7 +260,7 @@ namespace Mono.Xml.Schema
|
|
|
|
|
|
private void Init (XsdKeyTable keyseq, int depth, IXmlLineInfo li)
|
|
|
{
|
|
|
- KeySequence = keyseq;
|
|
|
+ OwnerSequence = keyseq;
|
|
|
KeyFields = new XsdKeyEntryFieldCollection ();
|
|
|
for (int i = 0; i < keyseq.Selector.Fields.Length; i++)
|
|
|
KeyFields.Add (new XsdKeyEntryField (this, keyseq.Selector.Fields [i]));
|
|
|
@@ -366,46 +289,49 @@ namespace Mono.Xml.Schema
|
|
|
}
|
|
|
|
|
|
// In this method, attributes are ignored.
|
|
|
- // It might throw Exception including non-XmlSchemaException.
|
|
|
- public void FieldMatches (ArrayList qnameStack, XsdValidatingReader reader)
|
|
|
+ // It might throw Exception.
|
|
|
+ public bool ProcessMatch (bool isAttribute, ArrayList qnameStack, object sender, XmlNameTable nameTable, string sourceUri, object schemaType, NSResolver nsResolver, IXmlLineInfo li, int depth, string attrName, string attrNS, string attrValue, bool isXsiNil, ArrayList currentKeyFieldConsumers)
|
|
|
{
|
|
|
+ bool found = false;
|
|
|
for (int i = 0; i < KeyFields.Count; i++) {
|
|
|
XsdKeyEntryField keyField = KeyFields [i];
|
|
|
- XsdIdentityPath path = keyField.FieldMatches (qnameStack, reader);
|
|
|
+ XsdIdentityPath path = keyField.Matches (isAttribute, sender, nameTable, qnameStack, sourceUri, schemaType, nsResolver, li, depth, attrName, attrNS, attrValue);
|
|
|
if (path != null) {
|
|
|
if (keyField.FieldFound) {
|
|
|
// HACK: This is not logical by nature. Attributes never be cosuming,
|
|
|
// so I used it as a temporary mark to sign it is *just* validated now.
|
|
|
+ // FIXME: This hack seems harmful here.
|
|
|
if (!keyField.Consuming)
|
|
|
throw new XmlSchemaException ("Two or more matching field was found.",
|
|
|
- reader, reader.BaseURI, this.KeySequence.SourceSchemaIdentity, null);
|
|
|
+ sender, sourceUri, this.OwnerSequence.SourceSchemaIdentity, null);
|
|
|
else
|
|
|
keyField.Consuming = false;
|
|
|
}
|
|
|
if (!keyField.Consumed) {
|
|
|
- if (reader.XsiNilDepth == reader.Depth && !keyField.SetIdentityField (Guid.Empty, true, XsdAnySimpleType.Instance, reader.Depth, (IXmlLineInfo) reader))
|
|
|
- throw new XmlSchemaException ("Two or more identical field was found.", reader, reader.BaseURI, KeySequence.SourceSchemaIdentity, null);
|
|
|
+ if (isXsiNil && !keyField.SetIdentityField (Guid.Empty, true, XsdAnySimpleType.Instance, depth, li))
|
|
|
+ throw new XmlSchemaException ("Two or more identical field was found.", sender, sourceUri, OwnerSequence.SourceSchemaIdentity, null);
|
|
|
else {
|
|
|
- XmlSchemaComplexType ct = reader.SchemaType as XmlSchemaComplexType;
|
|
|
+ XmlSchemaComplexType ct = schemaType as XmlSchemaComplexType;
|
|
|
if (ct != null &&
|
|
|
(ct.ContentType == XmlSchemaContentType.Empty || ct.ContentType == XmlSchemaContentType.ElementOnly) &&
|
|
|
- reader.SchemaType != XmlSchemaComplexType.AnyType)
|
|
|
- throw new XmlSchemaException ("Specified schema type is complex type, which is not allowed for identity constraints.", reader, reader.BaseURI, KeySequence.SourceSchemaIdentity, null);
|
|
|
+ schemaType != XmlSchemaComplexType.AnyType)
|
|
|
+ throw new XmlSchemaException ("Specified schema type is complex type, which is not allowed for identity constraints.", sender, sourceUri, OwnerSequence.SourceSchemaIdentity, null);
|
|
|
keyField.FieldFound = true;
|
|
|
keyField.FieldFoundPath = path;
|
|
|
- keyField.FieldFoundDepth = reader.Depth;
|
|
|
+ keyField.FieldFoundDepth = depth;
|
|
|
keyField.Consuming = true;
|
|
|
- IXmlLineInfo li = reader as IXmlLineInfo;
|
|
|
if (li != null && li.HasLineInfo ()) {
|
|
|
keyField.FieldHasLineInfo = true;
|
|
|
keyField.FieldLineNumber = li.LineNumber;
|
|
|
keyField.FieldLinePosition = li.LinePosition;
|
|
|
}
|
|
|
- reader.CurrentKeyFieldConsumers.Add (keyField);
|
|
|
+ currentKeyFieldConsumers.Add (keyField);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ found |= keyField.Consumed;
|
|
|
}
|
|
|
+ return found;
|
|
|
}
|
|
|
}
|
|
|
}
|