The Labs \ Source Viewer \ SSCLI \ System.Xml.Schema \ AxisStack

  1. //------------------------------------------------------------------------------
  2. // <copyright file="asttree.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Xml.Schema
  16. {
  17.     using System.Xml.XPath;
  18.     using System.Diagnostics;
  19.     using System.Globalization;
  20.     using System.IO;
  21.     using System.Collections;
  22.     using System.Xml.Schema;
  23.     using MS.Internal.Xml.XPath;
  24.    
  25. /*--------------------------------------------------------------------------------------------- *
  26.     * Dynamic Part Below...                                                                        *
  27.     * -------------------------------------------------------------------------------------------- */   
  28.    
  29.     // stack element class
  30.     // this one needn't change, even the parameter in methods
  31.     internal class AxisElement
  32.     {
  33.         internal DoubleLinkAxis curNode;
  34.         // current under-checking node during navigating
  35.         internal int rootDepth;
  36.         // root depth -- contextDepth + 1 if ! isDss; context + {1...} if isDss
  37.         internal int curDepth;
  38.         // current depth
  39.         internal bool isMatch;
  40.         // current is already matching or waiting for matching
  41.         internal DoubleLinkAxis CurNode {
  42.             get { return this.curNode; }
  43.         }
  44.        
  45.         // constructor
  46.         internal AxisElement(DoubleLinkAxis node, int depth)
  47.         {
  48.             this.curNode = node;
  49.             this.rootDepth = this.curDepth = depth;
  50.             this.isMatch = false;
  51.         }
  52.        
  53.         internal void SetDepth(int depth)
  54.         {
  55.             this.rootDepth = this.curDepth = depth;
  56.             return;
  57.         }
  58.        
  59.         // "a/b/c" pointer from b move to a
  60.         // needn't change even tree structure changes
  61.         internal void MoveToParent(int depth, ForwardAxis parent)
  62.         {
  63.             // "a/b/c", trying to match b (current node), but meet the end of a, so move pointer to a
  64.             if (depth == this.curDepth - 1) {
  65.                 // really need to move the current node pointer to parent
  66.                 // what i did here is for seperating the case of IsDss or only IsChild
  67.                 // bcoz in the first case i need to expect "a" from random depth
  68.                 // -1 means it doesn't expect some specific depth (referecing the dealing to -1 in movetochild method
  69.                 // while in the second case i can't change the root depth which is 1.
  70.                 if ((this.curNode.Input == parent.RootNode) && (parent.IsDss)) {
  71.                     this.curNode = parent.RootNode;
  72.                     this.rootDepth = this.curDepth = -1;
  73.                     return;
  74.                 }
  75.                 else if (this.curNode.Input != null) {
  76.                     // else cur-depth --, cur-node change
  77.                     this.curNode = (DoubleLinkAxis)(this.curNode.Input);
  78.                     this.curDepth--;
  79.                     return;
  80.                 }
  81.                 else
  82.                     return;
  83.             }
  84.             // "a/b/c", trying to match b (current node), but meet the end of x (another child of a)
  85.             // or maybe i matched, now move out the current node
  86.             // or move out after failing to match attribute
  87.             // the node i m next expecting is still the current node
  88.             else if (depth == this.curDepth) {
  89.                 // after matched or [2] failed in matching attribute
  90.                 if (this.isMatch) {
  91.                     this.isMatch = false;
  92.                 }
  93.             }
  94.             return;
  95.             // this node is still what i am expecting
  96.             // ignore
  97.         }
  98.        
  99.         // equal & ! attribute then move
  100.         // "a/b/c" pointer from a move to b
  101.         // return true if reach c and c is an element and c is the axis
  102.         internal bool MoveToChild(string name, string URN, int depth, ForwardAxis parent)
  103.         {
  104.             // an attribute can never be the same as an element
  105.             if (Asttree.IsAttribute(this.curNode)) {
  106.                 return false;
  107.             }
  108.            
  109.             // either moveToParent or moveToChild status will have to be changed into unmatch...
  110.             if (this.isMatch) {
  111.                 this.isMatch = false;
  112.             }
  113.             if (!AxisStack.Equal(this.curNode.Name, this.curNode.Urn, name, URN)) {
  114.                 return false;
  115.             }
  116.             if (this.curDepth == -1) {
  117.                 SetDepth(depth);
  118.             }
  119.             else if (depth > this.curDepth) {
  120.                 return false;
  121.             }
  122.             // matched ...
  123.             if (this.curNode == parent.TopNode) {
  124.                 this.isMatch = true;
  125.                 return true;
  126.             }
  127.             // move down this.curNode
  128.             DoubleLinkAxis nowNode = (DoubleLinkAxis)(this.curNode.Next);
  129.             if (Asttree.IsAttribute(nowNode)) {
  130.                 this.isMatch = true;
  131.                 // for attribute
  132.                 return false;
  133.             }
  134.             this.curNode = nowNode;
  135.             this.curDepth++;
  136.             return false;
  137.         }
  138.        
  139.     }
  140.    
  141.     internal class AxisStack
  142.     {
  143.         // property
  144.         private ArrayList stack;
  145.         // of AxisElement
  146.         private ForwardAxis subtree;
  147.         // reference to the corresponding subtree
  148.         private ActiveAxis parent;
  149.        
  150.         internal ForwardAxis Subtree {
  151.             get { return this.subtree; }
  152.         }
  153.        
  154.         internal int Length {
  155.             // stack length
  156.             get { return this.stack.Count; }
  157.         }
  158.        
  159.         // instructor
  160.         public AxisStack(ForwardAxis faxis, ActiveAxis parent)
  161.         {
  162.             this.subtree = faxis;
  163.             this.stack = new ArrayList();
  164.             this.parent = parent;
  165.             // need to use its contextdepth each time....
  166.             // improvement:
  167.             // if ! isDss, there has nothing to do with Push/Pop, only one copy each time will be kept
  168.             // if isDss, push and pop each time....
  169.             if (!faxis.IsDss) {
  170.                 // keep an instance
  171.                 this.Push(1);
  172.                 // context depth + 1
  173.             }
  174.             // else just keep stack empty
  175.         }
  176.        
  177.         // method
  178.         internal void Push(int depth)
  179.         {
  180.             AxisElement eaxis = new AxisElement(this.subtree.RootNode, depth);
  181.             this.stack.Add(eaxis);
  182.         }
  183.        
  184.         internal void Pop()
  185.         {
  186.             this.stack.RemoveAt(Length - 1);
  187.         }
  188.        
  189.         static internal bool Equal(string thisname, string thisURN, string name, string URN)
  190.         {
  191.             // which means "b" in xpath, no namespace should be specified
  192.             if (thisURN == null) {
  193.                 if (!((URN == null) || (URN.Length == 0))) {
  194.                     return false;
  195.                 }
  196.             }
  197.             // != "*"
  198.             else if ((thisURN.Length != 0) && (thisURN != URN)) {
  199.                 return false;
  200.             }
  201.             // != "a:*" || "*"
  202.             if ((thisname.Length != 0) && (thisname != name)) {
  203.                 return false;
  204.             }
  205.             return true;
  206.         }
  207.        
  208.         // "a/b/c" pointer from b move to a
  209.         // needn't change even tree structure changes
  210.         internal void MoveToParent(string name, string URN, int depth)
  211.         {
  212.             if (this.subtree.IsSelfAxis) {
  213.                 return;
  214.             }
  215.            
  216.             foreach (AxisElement eaxis in this.stack) {
  217.                 eaxis.MoveToParent(depth, this.subtree);
  218.             }
  219.            
  220.             // in ".//"'s case, since each time you push one new element while match, why not pop one too while match?
  221.             if (this.subtree.IsDss && Equal(this.subtree.RootNode.Name, this.subtree.RootNode.Urn, name, URN)) {
  222.                 Pop();
  223.             }
  224.             // only the last one
  225.         }
  226.        
  227.         // "a/b/c" pointer from a move to b
  228.         // return true if reach c
  229.         internal bool MoveToChild(string name, string URN, int depth)
  230.         {
  231.             bool result = false;
  232.             // push first
  233.             if (this.subtree.IsDss && Equal(this.subtree.RootNode.Name, this.subtree.RootNode.Urn, name, URN)) {
  234.                 Push(-1);
  235.             }
  236.             foreach (AxisElement eaxis in this.stack) {
  237.                 if (eaxis.MoveToChild(name, URN, depth, this.subtree)) {
  238.                     result = true;
  239.                 }
  240.             }
  241.             return result;
  242.         }
  243.        
  244.         // attribute can only at the topaxis part
  245.         // dealing with attribute only here, didn't go into stack element at all
  246.         // stack element only deal with moving the pointer around elements
  247.         internal bool MoveToAttribute(string name, string URN, int depth)
  248.         {
  249.             if (!this.subtree.IsAttribute) {
  250.                 return false;
  251.             }
  252.             if (!Equal(this.subtree.TopNode.Name, this.subtree.TopNode.Urn, name, URN)) {
  253.                 return false;
  254.             }
  255.            
  256.             bool result = false;
  257.            
  258.             // no stack element for single attribute, so dealing with it seperately
  259.             if (this.subtree.TopNode.Input == null) {
  260.                 return (this.subtree.IsDss || (depth == 1));
  261.             }
  262.            
  263.             foreach (AxisElement eaxis in this.stack) {
  264.                 if ((eaxis.isMatch) && (eaxis.CurNode == this.subtree.TopNode.Input)) {
  265.                     result = true;
  266.                 }
  267.             }
  268.             return result;
  269.         }
  270.        
  271.     }
  272.    
  273.     // whenever an element is under identity-constraint, an instance of this class will be called
  274.     // only care about property at this time
  275.     internal class ActiveAxis
  276.     {
  277.         private int currentDepth;
  278.         // current depth, trace the depth by myself... movetochild, movetoparent, movetoattribute
  279.         private bool isActive;
  280.         // not active any more after moving out context node
  281.         private Asttree axisTree;
  282.         // reference to the whole tree
  283.         // for each subtree i need to keep a stack...
  284.         private ArrayList axisStack;
  285.         // of AxisStack
  286.         public int CurrentDepth {
  287.             get { return this.currentDepth; }
  288.         }
  289.        
  290.         // if an instance is !IsActive, then it can be reactive and reuse
  291.         // still need thinking.....
  292.         internal void Reactivate()
  293.         {
  294.             this.isActive = true;
  295.             this.currentDepth = -1;
  296.         }
  297.        
  298.         internal ActiveAxis(Asttree axisTree)
  299.         {
  300.             this.axisTree = axisTree;
  301.             // only a pointer. do i need it?
  302.             this.currentDepth = -1;
  303.             // context depth is 0 -- enforce moveToChild for the context node
  304.             // otherwise can't deal with "." node
  305.             this.axisStack = new ArrayList(axisTree.SubtreeArray.Count);
  306.             // defined length
  307.             // new one stack element for each one
  308.             foreach (ForwardAxis faxis in axisTree.SubtreeArray) {
  309.                 AxisStack stack = new AxisStack(faxis, this);
  310.                 axisStack.Add(stack);
  311.             }
  312.             this.isActive = true;
  313.         }
  314.        
  315.         public bool MoveToStartElement(string localname, string URN)
  316.         {
  317.             if (!isActive) {
  318.                 return false;
  319.             }
  320.            
  321.             // for each:
  322.             this.currentDepth++;
  323.             bool result = false;
  324.             foreach (AxisStack stack in this.axisStack) {
  325.                 // special case for self tree "." | ".//."
  326.                 if (stack.Subtree.IsSelfAxis) {
  327.                     if (stack.Subtree.IsDss || (this.CurrentDepth == 0))
  328.                         result = true;
  329.                     continue;
  330.                 }
  331.                
  332.                 // otherwise if it's context node then return false
  333.                 if (this.CurrentDepth == 0)
  334.                     continue;
  335.                
  336.                 if (stack.MoveToChild(localname, URN, this.currentDepth)) {
  337.                     result = true;
  338.                     // even already know the last result is true, still need to continue...
  339.                     // run everyone once
  340.                 }
  341.             }
  342.             return result;
  343.         }
  344.        
  345.         // return result doesn't have any meaning until in SelectorActiveAxis
  346.         public virtual bool EndElement(string localname, string URN)
  347.         {
  348.             // need to think if the early quitting will affect reactivating....
  349.             if (this.currentDepth == 0) {
  350.                 // leave context node
  351.                 this.isActive = false;
  352.                 this.currentDepth--;
  353.             }
  354.             if (!this.isActive) {
  355.                 return false;
  356.             }
  357.             foreach (AxisStack stack in this.axisStack) {
  358.                 stack.MoveToParent(localname, URN, this.currentDepth);
  359.             }
  360.             this.currentDepth--;
  361.             return false;
  362.         }
  363.        
  364.         // Secondly field interface
  365.         public bool MoveToAttribute(string localname, string URN)
  366.         {
  367.             if (!this.isActive) {
  368.                 return false;
  369.             }
  370.             bool result = false;
  371.             foreach (AxisStack stack in this.axisStack) {
  372.                 if (stack.MoveToAttribute(localname, URN, this.currentDepth + 1)) {
  373.                     // don't change depth for attribute, but depth is add 1
  374.                     result = true;
  375.                 }
  376.             }
  377.             return result;
  378.         }
  379.     }
  380.    
  381. /* ---------------------------------------------------------------------------------------------- *
  382.     * Static Part Below...                                                                          *
  383.     * ---------------------------------------------------------------------------------------------- */   
  384.    
  385.     // each node in the xpath tree
  386.     internal class DoubleLinkAxis : Axis
  387.     {
  388.         internal Axis next;
  389.        
  390.         internal Axis Next {
  391.             get { return this.next; }
  392.             set { this.next = value; }
  393.         }
  394.        
  395.         //constructor
  396.         internal DoubleLinkAxis(Axis axis, DoubleLinkAxis inputaxis) : base(axis.TypeOfAxis, inputaxis, axis.Prefix, axis.Name, axis.NodeType)
  397.         {
  398.             this.next = null;
  399.             this.Urn = axis.Urn;
  400.             this.abbrAxis = axis.AbbrAxis;
  401.             if (inputaxis != null) {
  402.                 inputaxis.Next = this;
  403.             }
  404.         }
  405.        
  406.         // recursive here
  407.         static internal DoubleLinkAxis ConvertTree(Axis axis)
  408.         {
  409.             if (axis == null) {
  410.                 return null;
  411.             }
  412.             return (new DoubleLinkAxis(axis, ConvertTree((Axis)(axis.Input))));
  413.         }
  414.     }
  415.    
  416.    
  417.    
  418.     // only keep axis, rootNode, isAttribute, isDss inside
  419.     // act as an element tree for the Asttree
  420.     internal class ForwardAxis
  421.     {
  422.         // Axis tree
  423.         private DoubleLinkAxis topNode;
  424.         private DoubleLinkAxis rootNode;
  425.         // the root for reverse Axis
  426.         // Axis tree property
  427.         private bool isAttribute;
  428.         // element or attribute? "@"?
  429.         private bool isDss;
  430.         // has ".//" in front of it?
  431.         private bool isSelfAxis;
  432.         // only one node in the tree, and it's "." (self) node
  433.         internal DoubleLinkAxis RootNode {
  434.             get { return this.rootNode; }
  435.         }
  436.        
  437.         internal DoubleLinkAxis TopNode {
  438.             get { return this.topNode; }
  439.         }
  440.        
  441.         internal bool IsAttribute {
  442.             get { return this.isAttribute; }
  443.         }
  444.        
  445.         // has ".//" in front of it?
  446.         internal bool IsDss {
  447.             get { return this.isDss; }
  448.         }
  449.        
  450.         internal bool IsSelfAxis {
  451.             get { return this.isSelfAxis; }
  452.         }
  453.        
  454.         public ForwardAxis(DoubleLinkAxis axis, bool isdesorself)
  455.         {
  456.             this.isDss = isdesorself;
  457.             this.isAttribute = Asttree.IsAttribute(axis);
  458.             this.topNode = axis;
  459.             this.rootNode = axis;
  460.             while (this.rootNode.Input != null) {
  461.                 this.rootNode = (DoubleLinkAxis)(this.rootNode.Input);
  462.             }
  463.             // better to calculate it out, since it's used so often, and if the top is self then the whole tree is self
  464.             this.isSelfAxis = Asttree.IsSelf(this.topNode);
  465.         }
  466.     }
  467.    
  468.     // static, including an array of ForwardAxis (this is the whole picture)
  469.     internal class Asttree
  470.     {
  471.         // set private then give out only get access, to keep it intact all along
  472.         private ArrayList fAxisArray;
  473.         private string xpathexpr;
  474.         private bool isField;
  475.         // field or selector
  476.         private XmlNamespaceManager nsmgr;
  477.        
  478.         internal ArrayList SubtreeArray {
  479.             get { return fAxisArray; }
  480.         }
  481.        
  482.         // when making a new instance for Asttree, we do the compiling, and create the static tree instance
  483.         public Asttree(string xPath, bool isField, XmlNamespaceManager nsmgr)
  484.         {
  485.             this.xpathexpr = xPath;
  486.             this.isField = isField;
  487.             this.nsmgr = nsmgr;
  488.             // checking grammar... and build fAxisArray
  489.             this.CompileXPath(xPath, isField, nsmgr);
  490.             // might throw exception in the middle
  491.         }
  492.        
  493.         // only for debug
  494.         #if DEBUG
  495.         public void PrintTree(StreamWriter msw)
  496.         {
  497.             foreach (ForwardAxis axis in fAxisArray) {
  498.                 msw.WriteLine("<Tree IsDss=\"{0}\" IsAttribute=\"{1}\">", axis.IsDss, axis.IsAttribute);
  499.                 DoubleLinkAxis printaxis = axis.TopNode;
  500.                 while (printaxis != null) {
  501.                     msw.WriteLine(" <node>");
  502.                     msw.WriteLine(" <URN> {0} </URN>", printaxis.Urn);
  503.                     msw.WriteLine(" <Prefix> {0} </Prefix>", printaxis.Prefix);
  504.                     msw.WriteLine(" <Name> {0} </Name>", printaxis.Name);
  505.                     msw.WriteLine(" <NodeType> {0} </NodeType>", printaxis.NodeType);
  506.                     msw.WriteLine(" <AxisType> {0} </AxisType>", printaxis.TypeOfAxis);
  507.                     msw.WriteLine(" </node>");
  508.                     printaxis = (DoubleLinkAxis)(printaxis.Input);
  509.                 }
  510.                 msw.WriteLine("</Tree>");
  511.             }
  512.         }
  513.         #endif
  514.        
  515.         // this part is for parsing restricted xpath from grammar
  516.         private static bool IsNameTest(Axis ast)
  517.         {
  518.             // Type = Element, abbrAxis = false
  519.             // all are the same, has child:: or not
  520.             return ((ast.TypeOfAxis == Axis.AxisType.Child) && (ast.NodeType == XPathNodeType.Element));
  521.         }
  522.        
  523.         static internal bool IsAttribute(Axis ast)
  524.         {
  525.             return ((ast.TypeOfAxis == Axis.AxisType.Attribute) && (ast.NodeType == XPathNodeType.Attribute));
  526.         }
  527.        
  528.         private static bool IsDescendantOrSelf(Axis ast)
  529.         {
  530.             return ((ast.TypeOfAxis == Axis.AxisType.DescendantOrSelf) && (ast.NodeType == XPathNodeType.All) && (ast.AbbrAxis));
  531.         }
  532.        
  533.         static internal bool IsSelf(Axis ast)
  534.         {
  535.             return ((ast.TypeOfAxis == Axis.AxisType.Self) && (ast.NodeType == XPathNodeType.All) && (ast.AbbrAxis));
  536.         }
  537.        
  538.         // don't return true or false, if it's invalid path, just throw exception during the process
  539.         // for whitespace thing, i will directly trim the tree built here...
  540.         public void CompileXPath(string xPath, bool isField, XmlNamespaceManager nsmgr)
  541.         {
  542.             if ((xPath == null) || (xPath.Length == 0)) {
  543.                 throw new XmlSchemaException(Res.Sch_EmptyXPath, string.Empty);
  544.             }
  545.            
  546.             // firstly i still need to have an ArrayList to store tree only...
  547.             // can't new ForwardAxis right away
  548.             string[] xpath = xPath.Split('|');
  549.             ArrayList AstArray = new ArrayList(xpath.Length);
  550.             this.fAxisArray = new ArrayList(xpath.Length);
  551.            
  552.             // throw compile exceptions
  553.             // can i only new one builder here then run compile several times??
  554.             try {
  555.                 foreach (string value in xpath) {
  556.                     // default ! isdesorself (no .//)
  557.                     Axis ast = (Axis)(XPathParser.ParseXPathExpresion(value));
  558.                     AstArray.Add(ast);
  559.                 }
  560.             }
  561.             catch {
  562.                 throw new XmlSchemaException(Res.Sch_ICXpathError, xPath);
  563.             }
  564.            
  565.             Axis stepAst;
  566.             foreach (Axis ast in AstArray) {
  567.                 // Restricted form
  568.                 // field can have an attribute:
  569.                
  570.                 // throw exceptions during casting
  571.                 if ((stepAst = ast) == null) {
  572.                     throw new XmlSchemaException(Res.Sch_ICXpathError, xPath);
  573.                 }
  574.                
  575.                 Axis top = stepAst;
  576.                
  577.                 // attribute will have namespace too
  578.                 // field can have top attribute
  579.                 if (IsAttribute(stepAst)) {
  580.                     if (!isField) {
  581.                         throw new XmlSchemaException(Res.Sch_SelectorAttr, xPath);
  582.                     }
  583.                     else {
  584.                         SetURN(stepAst, nsmgr);
  585.                         try {
  586.                             stepAst = (Axis)(stepAst.Input);
  587.                         }
  588.                         catch {
  589.                             throw new XmlSchemaException(Res.Sch_ICXpathError, xPath);
  590.                         }
  591.                     }
  592.                 }
  593.                
  594.                 // field or selector
  595.                 while ((stepAst != null) && (IsNameTest(stepAst) || IsSelf(stepAst))) {
  596.                     // trim tree "." node, if it's not the top one
  597.                     if (IsSelf(stepAst) && (ast != stepAst)) {
  598.                         top.Input = stepAst.Input;
  599.                     }
  600.                     else {
  601.                         top = stepAst;
  602.                         // set the URN
  603.                         if (IsNameTest(stepAst)) {
  604.                             SetURN(stepAst, nsmgr);
  605.                         }
  606.                     }
  607.                     try {
  608.                         stepAst = (Axis)(stepAst.Input);
  609.                     }
  610.                     catch {
  611.                         throw new XmlSchemaException(Res.Sch_ICXpathError, xPath);
  612.                     }
  613.                 }
  614.                
  615.                 // the rest part can only be .// or null
  616.                 // trim the rest part, but need compile the rest part first
  617.                 top.Input = null;
  618.                 if (stepAst == null) {
  619.                     // top "." and has other element beneath, trim this "." node too
  620.                     if (IsSelf(ast) && (ast.Input != null)) {
  621.                         this.fAxisArray.Add(new ForwardAxis(DoubleLinkAxis.ConvertTree((Axis)(ast.Input)), false));
  622.                     }
  623.                     else {
  624.                         this.fAxisArray.Add(new ForwardAxis(DoubleLinkAxis.ConvertTree(ast), false));
  625.                     }
  626.                     continue;
  627.                 }
  628.                 if (!IsDescendantOrSelf(stepAst)) {
  629.                     throw new XmlSchemaException(Res.Sch_ICXpathError, xPath);
  630.                 }
  631.                 try {
  632.                     stepAst = (Axis)(stepAst.Input);
  633.                 }
  634.                 catch {
  635.                     throw new XmlSchemaException(Res.Sch_ICXpathError, xPath);
  636.                 }
  637.                 if ((stepAst == null) || (!IsSelf(stepAst)) || (stepAst.Input != null)) {
  638.                     throw new XmlSchemaException(Res.Sch_ICXpathError, xPath);
  639.                 }
  640.                
  641.                 // trim top "." if it's not the only node
  642.                 if (IsSelf(ast) && (ast.Input != null)) {
  643.                     this.fAxisArray.Add(new ForwardAxis(DoubleLinkAxis.ConvertTree((Axis)(ast.Input)), true));
  644.                 }
  645.                 else {
  646.                     this.fAxisArray.Add(new ForwardAxis(DoubleLinkAxis.ConvertTree(ast), true));
  647.                 }
  648.             }
  649.         }
  650.        
  651.         // depending on axis.Name & axis.Prefix, i will set the axis.URN;
  652.         // also, record urn from prefix during this
  653.         // 4 different types of element or attribute (with @ before it) combinations:
  654.         // (1) a:b (2) b (3) * (4) a:*
  655.         // i will check xpath to be strictly conformed from these forms
  656.         // for (1) & (4) i will have URN set properly
  657.         // for (2) the URN is null
  658.         // for (3) the URN is empty
  659.         private void SetURN(Axis axis, XmlNamespaceManager nsmgr)
  660.         {
  661.             if (axis.Prefix.Length != 0) {
  662.                 // (1) (4)
  663.                 axis.Urn = nsmgr.LookupNamespace(axis.Prefix);
  664.                
  665.                 if (axis.Urn == null) {
  666.                     throw new XmlSchemaException(Res.Sch_UnresolvedPrefix, axis.Prefix);
  667.                 }
  668.             }
  669.             else if (axis.Name.Length != 0) {
  670.                 // (2)
  671.                 axis.Urn = null;
  672.             }
  673.             else {
  674.                 // (3)
  675.                 axis.Urn = "";
  676.             }
  677.         }
  678.     }
  679.     // Asttree
  680. }

Developer Fusion