Mass removal of all Tabs (Style Warnings)
[aaf/authz.git] / cadi / core / src / main / java / org / onap / aaf / cadi / wsse / XReader.java
index 78265e4..b7cc40a 100644 (file)
@@ -49,379 +49,379 @@ import javax.xml.stream.XMLStreamException;
  */
 // @SuppressWarnings("restriction")
 public class XReader {
-       private XEvent curr,another;
-       private InputStream is;
-       private ByteArrayOutputStream baos;
-       private int state, count, last;
-       
-       private Stack<Map<String,String>> nsses;
-       
-       public XReader(InputStream is) {
-               this.is = is;
-               curr = another = null;
-               baos = new ByteArrayOutputStream();
-               state = BEGIN_DOC; 
-               count = 0;
-               nsses = new Stack<Map<String,String>>();
-       }
-       
-       public boolean hasNext() throws XMLStreamException {
-               if(curr==null) {
-                       curr = parse();
-               }
-               return curr!=null;
-       }
+    private XEvent curr,another;
+    private InputStream is;
+    private ByteArrayOutputStream baos;
+    private int state, count, last;
+    
+    private Stack<Map<String,String>> nsses;
+    
+    public XReader(InputStream is) {
+        this.is = is;
+        curr = another = null;
+        baos = new ByteArrayOutputStream();
+        state = BEGIN_DOC; 
+        count = 0;
+        nsses = new Stack<Map<String,String>>();
+    }
+    
+    public boolean hasNext() throws XMLStreamException {
+        if(curr==null) {
+            curr = parse();
+        }
+        return curr!=null;
+    }
 
-       public XEvent nextEvent() {
-               XEvent xe = curr;
-               curr = null;
-               return xe;
-       }
+    public XEvent nextEvent() {
+        XEvent xe = curr;
+        curr = null;
+        return xe;
+    }
 
-       // 
-       // State Flags
-       //
-       // Note: The State of parsing XML can be complicated.  There are too many to cleanly keep in "booleans".  Additionally,
-       // there are certain checks that can be better made with Bitwise operations within switches
-       // Keeping track of state this way also helps us to accomplish logic without storing any back characters except one
-       private final static int BEGIN_DOC=  0x000001;
-       private final static int DOC_TYPE=   0x000002;
-       private final static int QUESTION_F= 0x000004;
-       private final static int QUESTION =  0x000008;
-       private final static int START_TAG = 0x000010;
-       private final static int END_TAG =       0x000020;
-       private final static int VALUE=          0x000040;
-       private final static int COMMENT =   0x001000;
-       private final static int COMMENT_E = 0x002000;
-       private final static int COMMENT_D1 =0x010000;
-       private final static int COMMENT_D2 =0x020000;
-       private final static int COMMENT_D3 =0x040000;
-       private final static int COMMENT_D4 =0x080000;
-       // useful combined Comment states
-       private final static int IN_COMMENT=COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2;
-       private final static int COMPLETE_COMMENT = COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2|COMMENT_D3|COMMENT_D4;
-       
-       
-       private XEvent parse() throws XMLStreamException {
-               Map<String,String> nss = nsses.isEmpty()?null:nsses.peek();
+    // 
+    // State Flags
+    //
+    // Note: The State of parsing XML can be complicated.  There are too many to cleanly keep in "booleans".  Additionally,
+    // there are certain checks that can be better made with Bitwise operations within switches
+    // Keeping track of state this way also helps us to accomplish logic without storing any back characters except one
+    private final static int BEGIN_DOC=  0x000001;
+    private final static int DOC_TYPE=   0x000002;
+    private final static int QUESTION_F= 0x000004;
+    private final static int QUESTION =  0x000008;
+    private final static int START_TAG = 0x000010;
+    private final static int END_TAG =      0x000020;
+    private final static int VALUE=         0x000040;
+    private final static int COMMENT =   0x001000;
+    private final static int COMMENT_E = 0x002000;
+    private final static int COMMENT_D1 =0x010000;
+    private final static int COMMENT_D2 =0x020000;
+    private final static int COMMENT_D3 =0x040000;
+    private final static int COMMENT_D4 =0x080000;
+    // useful combined Comment states
+    private final static int IN_COMMENT=COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2;
+    private final static int COMPLETE_COMMENT = COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2|COMMENT_D3|COMMENT_D4;
+    
+    
+    private XEvent parse() throws XMLStreamException {
+        Map<String,String> nss = nsses.isEmpty()?null:nsses.peek();
 
-               XEvent rv;
-               if((rv=another)!=null) { // "another" is a tag that may have needed to be created, but not 
-                                                                // immediately returned.  Save for next parse.  If necessary, this could be turned into
-                                                                // a FIFO storage, but a single reference is enough for now.
-                       another = null;      // "rv" is now set for the Event, and will be returned.  Set to Null.
-               } else {
-                       boolean go = true;
-                       int c=0;
-                       
-                       try {
-                               while(go && (c=is.read())>=0) {
-                                       ++count;
-                                       switch(c) {
-                                               case '<': // Tag is opening
-                                                       state|=~BEGIN_DOC; // remove BEGIN_DOC flag, this is possibly an XML Doc
-                                                       XEvent cxe = null;
-                                                       if(baos.size()>0) { // If there are any characters between tags, we send as Character Event
-                                                               String chars = baos.toString().trim();  // Trim out WhiteSpace before and after
-                                                               if(chars.length()>0) { // don't send if Characters were only whitespace
-                                                                       cxe = new XEvent.Characters(chars);
-                                                                       baos.reset();
-                                                                       go = false;
-                                                               }
-                                                       }
-                                                       last = c;  // make sure "last" character is set for use in "ParseTag"
-                                                       Tag t = parseTag(); // call subroutine to process the tag as a unit
-                                                       String ns;
-                                                       switch(t.state&(START_TAG|END_TAG)) {
-                                                               case START_TAG:
-                                                                               nss = getNss(nss,t);                    // Only Start Tags might have NS Attributes   
-                                                                                                                                               // Get any NameSpace elements from tag.  If there are, nss will become 
-                                                                                                                                               // a new Map with all the previous NSs plus the new.  This provides 
-                                                                                                                                               // scoping behavior when used with the Stack
-                                                                       // drop through on purpose
-                                                               case END_TAG:
-                                                                       ns = t.prefix==null||nss==null?"":nss.get(t.prefix); // Get the namespace from prefix (if exists)
-                                                                       break;
-                                                               default:
-                                                                       ns = "";
-                                                       }
-                                                       if(ns==null)
-                                                               throw new XMLStreamException("Invalid Namespace Prefix at " + count);
-                                                       go = false;
-                                                       switch(t.state) { // based on 
-                                                         case DOC_TYPE: 
-                                                                 rv = new XEvent.StartDocument();
-                                                                 break;
-                                                         case COMMENT:
-                                                                 rv = new XEvent.Comment(t.value);
-                                                                 break;
-                                                         case START_TAG:
-                                                                 rv = new XEvent.StartElement(ns,t.name);
-                                                                 nsses.push(nss);                              // Change potential scope for Namespace
-                                                                 break;
-                                                         case END_TAG:
-                                                                 rv = new XEvent.EndElement(ns,t.name);
-                                                                 nss = nsses.pop();                    // End potential scope for Namespace
-                                                                 break;
-                                                         case START_TAG|END_TAG:                       // This tag is both start/end  aka <myTag/>
-                                                                 rv = new XEvent.StartElement(ns,t.name);
-                                                                 if(last=='/')another = new XEvent.EndElement(ns,t.name);
-                                                       }
-                                                       if(cxe!=null) {     // if there is a Character Event, it actually should go first.  ow.
-                                                               another = rv;   // Make current Event the "another" or next event, and 
-                                                               rv = cxe;               // send Character Event now
-                                                       }
-                                                       break;
-                                               case ' ':
-                                               case '\t':
-                                               case '\n':
-                                                       if((state&BEGIN_DOC)==BEGIN_DOC) { // if Whitespace before doc, just ignore 
-                                                               break;
-                                                       }
-                                                       // fallthrough on purpose
-                                               default:
-                                                       if((state&BEGIN_DOC)==BEGIN_DOC) { // if there is any data at the start other than XML Tag, it's not XML
-                                                               throw new XMLStreamException("Parse Error: This is not an XML Doc");
-                                                       }
-                                                       baos.write(c); // save off Characters
-                                       }
-                                       last = c; // Some processing needs to know what the last character was, aka Escaped characters... ex \"
-                               }
-                       } catch (IOException e) {
-                               throw new XMLStreamException(e); // all errors parsing will be treated as XMLStreamErrors (like StAX)
-                       }
-                       if(c==-1 && (state&BEGIN_DOC)==BEGIN_DOC) {                        // Normally, end of stream is ok, however, we need to know if the 
-                               throw new XMLStreamException("Premature End of File"); // document isn't an XML document, so we throw exception if it 
-                       }                                                                                                                  // hasn't yet been determined to be an XML Doc
-               }
-               return rv;
-       }
-       
-       /**
-        * parseTag
-        
-        * Parsing a Tag is somewhat complicated, so it's helpful to separate this process from the 
-        * higher level Parsing effort
-        * @return
-        * @throws IOException
-        * @throws XMLStreamException
-        */
-       private Tag parseTag() throws IOException, XMLStreamException {
-               Tag tag = null;
-               boolean go = true;
-               state = 0;
-               int c, quote=0; // If "quote" is 0, then we're not in a quote.  We set ' (in pretag) or " in attribs accordingly to denote quoted
-               String prefix=null,name=null,value=null;
-               baos.reset();
-               
-               while(go && (c=is.read())>=0) {
-                       ++count;
-                       if(quote!=0) { // If we're in a quote, we only end if we hit another quote of the same time, not preceded by \
-                               if(c==quote && last!='\\') {
-                                       quote=0;
-                               } else {
-                                       baos.write(c);
-                               }
-                       } else if((state&COMMENT)==COMMENT) { // similar to Quote is being in a comment
-                               switch(c) {
-                                       case '-':
-                                               switch(state) { // XML has a complicated Quote set... <!-- --> ... we keep track if each has been met with flags. 
-                                                       case COMMENT|COMMENT_E:
-                                                               state|=COMMENT_D1;
-                                                               break;
-                                                       case COMMENT|COMMENT_E|COMMENT_D1:
-                                                               state|=COMMENT_D2;
-                                                               baos.reset();                           // clear out "!--", it's a Comment
-                                                               break;
-                                                       case COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2:
-                                                               state|=COMMENT_D3;
-                                                               baos.write(c);
-                                                               break;
-                                                       case COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2|COMMENT_D3:
-                                                               state|=COMMENT_D4;
-                                                               baos.write(c);
-                                                               break;
-                                               }
-                                               break;
-                                       case '>': // Tag indicator has been found, do we have all the comment characters in line?
-                                               if((state&COMPLETE_COMMENT)==COMPLETE_COMMENT) {
-                                                       byte ba[] = baos.toByteArray();
-                                                       tag = new Tag(null,null, new String(ba,0,ba.length-2));
-                                                       baos.reset();
-                                                       go = false;
-                                                       break;
-                                               }
-                                               // fall through on purpose
-                                       default:
-                                               state&=~(COMMENT_D3|COMMENT_D4);
-                                               if((state&IN_COMMENT)!=IN_COMMENT) state&=~IN_COMMENT; // false alarm, it's not actually a comment
-                                               baos.write(c);
-                               }
-                       } else { // Normal Tag Processing loop
-                               switch(c) {
-                                       case '?': 
-                                               switch(state & (QUESTION_F|QUESTION)) {  // Validate the state of Doc tag... <?xml ... ?>
-                                                       case QUESTION_F:
-                                                               state |= DOC_TYPE;
-                                                               state &= ~QUESTION_F;
-                                                               break;
-                                                       case 0:
-                                                               state |=QUESTION_F;
-                                                               break;
-                                                       default:
-                                                               throw new IOException("Bad character [?] at " + count);
-                                               }
-                                               break;
-                                       case '!':
-                                               if(last=='<') { 
-                                                       state|=COMMENT|COMMENT_E; // likely a comment, continue processing in Comment Loop
-                                               }
-                                               baos.write(c);
-                                               break;
-                                       case '/':
-                                               state|=(last=='<'?END_TAG:(END_TAG|START_TAG));  // end tag indicator </xxx>, ,or both <xxx/>
-                                               break;
-                                       case ':':
-                                               prefix=baos.toString(); // prefix indicator
-                                               baos.reset();
-                                               break;
-                                       case '=':                                       // used in Attributes
-                                               name=baos.toString();
-                                               baos.reset();
-                                               state|=VALUE;
-                                               break;
-                                       case '>': // end the tag, which causes end of this subprocess as well as formulation of the found data
-                                               go = false;
-                                               // passthrough on purpose
-                                       case ' ':
-                                       case '\t':
-                                       case '\n': // white space indicates change in internal tag state, ex between name and between attributes
-                                               if((state&VALUE)==VALUE) {
-                                                       value = baos.toString();        // we're in VALUE state, add characters to Value
-                                               } else if(name==null) {
-                                                       name = baos.toString();         // we're in Name state (default) add characters to Name
-                                               }
-                                               baos.reset();                                   // we've assigned chars, reset buffer
-                                               if(name!=null) {                                // Name is not null, there's a tag in the offing here...
-                                                       Tag t = new Tag(prefix,name,value);
-                                                       if(tag==null) {                         // Set as the tag to return, if not exists
-                                                               tag = t;
-                                                       } else {                                        // if we already have a Tag, then we'll treat this one as an attribute
-                                                               tag.add(t);
-                                                       }
-                                               }
-                                               prefix=name=value=null;                 // reset these values in case we loop for attributes.
-                                               break;
-                                       case '\'':                                                      // is the character one of two kinds of quote?
-                                       case '"':
-                                               if(last!='\\') {
-                                                       quote=c;
-                                                       break;
-                                               }
-                                               // Fallthrough ok
-                                       default:
-                                               baos.write(c);                                  // write any unprocessed bytes into buffer
-                                               
-                               }
-                       }
-                       last = c;
-               }
-               int type = state&(DOC_TYPE|COMMENT|END_TAG|START_TAG); // get just the Tag states and turn into Type for Tag
-               if(type==0) {
-                       type=START_TAG;
-               }
-               if(tag!=null) {
-                       tag.state|=type;        // add the appropriate Tag States
-               }
-               return tag;
-       }
+        XEvent rv;
+        if((rv=another)!=null) { // "another" is a tag that may have needed to be created, but not 
+                                 // immediately returned.  Save for next parse.  If necessary, this could be turned into
+                                 // a FIFO storage, but a single reference is enough for now.
+            another = null;      // "rv" is now set for the Event, and will be returned.  Set to Null.
+        } else {
+            boolean go = true;
+            int c=0;
+            
+            try {
+                while(go && (c=is.read())>=0) {
+                    ++count;
+                    switch(c) {
+                        case '<': // Tag is opening
+                            state|=~BEGIN_DOC; // remove BEGIN_DOC flag, this is possibly an XML Doc
+                            XEvent cxe = null;
+                            if(baos.size()>0) { // If there are any characters between tags, we send as Character Event
+                                String chars = baos.toString().trim();  // Trim out WhiteSpace before and after
+                                if(chars.length()>0) { // don't send if Characters were only whitespace
+                                    cxe = new XEvent.Characters(chars);
+                                    baos.reset();
+                                    go = false;
+                                }
+                            }
+                            last = c;  // make sure "last" character is set for use in "ParseTag"
+                            Tag t = parseTag(); // call subroutine to process the tag as a unit
+                            String ns;
+                            switch(t.state&(START_TAG|END_TAG)) {
+                                case START_TAG:
+                                        nss = getNss(nss,t);             // Only Start Tags might have NS Attributes   
+                                                                        // Get any NameSpace elements from tag.  If there are, nss will become 
+                                                                        // a new Map with all the previous NSs plus the new.  This provides 
+                                                                        // scoping behavior when used with the Stack
+                                    // drop through on purpose
+                                case END_TAG:
+                                    ns = t.prefix==null||nss==null?"":nss.get(t.prefix); // Get the namespace from prefix (if exists)
+                                    break;
+                                default:
+                                    ns = "";
+                            }
+                            if(ns==null)
+                                throw new XMLStreamException("Invalid Namespace Prefix at " + count);
+                            go = false;
+                            switch(t.state) { // based on 
+                              case DOC_TYPE: 
+                                  rv = new XEvent.StartDocument();
+                                  break;
+                              case COMMENT:
+                                  rv = new XEvent.Comment(t.value);
+                                  break;
+                              case START_TAG:
+                                  rv = new XEvent.StartElement(ns,t.name);
+                                  nsses.push(nss);                // Change potential scope for Namespace
+                                  break;
+                              case END_TAG:
+                                  rv = new XEvent.EndElement(ns,t.name);
+                                  nss = nsses.pop();            // End potential scope for Namespace
+                                  break;
+                              case START_TAG|END_TAG:            // This tag is both start/end  aka <myTag/>
+                                  rv = new XEvent.StartElement(ns,t.name);
+                                  if(last=='/')another = new XEvent.EndElement(ns,t.name);
+                            }
+                            if(cxe!=null) {     // if there is a Character Event, it actually should go first.  ow.
+                                another = rv;   // Make current Event the "another" or next event, and 
+                                rv = cxe;        // send Character Event now
+                            }
+                            break;
+                        case ' ':
+                        case '\t':
+                        case '\n':
+                            if((state&BEGIN_DOC)==BEGIN_DOC) { // if Whitespace before doc, just ignore 
+                                break;
+                            }
+                            // fallthrough on purpose
+                        default:
+                            if((state&BEGIN_DOC)==BEGIN_DOC) { // if there is any data at the start other than XML Tag, it's not XML
+                                throw new XMLStreamException("Parse Error: This is not an XML Doc");
+                            }
+                            baos.write(c); // save off Characters
+                    }
+                    last = c; // Some processing needs to know what the last character was, aka Escaped characters... ex \"
+                }
+            } catch (IOException e) {
+                throw new XMLStreamException(e); // all errors parsing will be treated as XMLStreamErrors (like StAX)
+            }
+            if(c==-1 && (state&BEGIN_DOC)==BEGIN_DOC) {                // Normally, end of stream is ok, however, we need to know if the 
+                throw new XMLStreamException("Premature End of File"); // document isn't an XML document, so we throw exception if it 
+            }                                                           // hasn't yet been determined to be an XML Doc
+        }
+        return rv;
+    }
+    
+    /**
+     * parseTag
+     * 
+     * Parsing a Tag is somewhat complicated, so it's helpful to separate this process from the 
+     * higher level Parsing effort
+     * @return
+     * @throws IOException
+     * @throws XMLStreamException
+     */
+    private Tag parseTag() throws IOException, XMLStreamException {
+        Tag tag = null;
+        boolean go = true;
+        state = 0;
+        int c, quote=0; // If "quote" is 0, then we're not in a quote.  We set ' (in pretag) or " in attribs accordingly to denote quoted
+        String prefix=null,name=null,value=null;
+        baos.reset();
+        
+        while(go && (c=is.read())>=0) {
+            ++count;
+            if(quote!=0) { // If we're in a quote, we only end if we hit another quote of the same time, not preceded by \
+                if(c==quote && last!='\\') {
+                    quote=0;
+                } else {
+                    baos.write(c);
+                }
+            } else if((state&COMMENT)==COMMENT) { // similar to Quote is being in a comment
+                switch(c) {
+                    case '-':
+                        switch(state) { // XML has a complicated Quote set... <!-- --> ... we keep track if each has been met with flags. 
+                            case COMMENT|COMMENT_E:
+                                state|=COMMENT_D1;
+                                break;
+                            case COMMENT|COMMENT_E|COMMENT_D1:
+                                state|=COMMENT_D2;
+                                baos.reset();                // clear out "!--", it's a Comment
+                                break;
+                            case COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2:
+                                state|=COMMENT_D3;
+                                baos.write(c);
+                                break;
+                            case COMMENT|COMMENT_E|COMMENT_D1|COMMENT_D2|COMMENT_D3:
+                                state|=COMMENT_D4;
+                                baos.write(c);
+                                break;
+                        }
+                        break;
+                    case '>': // Tag indicator has been found, do we have all the comment characters in line?
+                        if((state&COMPLETE_COMMENT)==COMPLETE_COMMENT) {
+                            byte ba[] = baos.toByteArray();
+                            tag = new Tag(null,null, new String(ba,0,ba.length-2));
+                            baos.reset();
+                            go = false;
+                            break;
+                        }
+                        // fall through on purpose
+                    default:
+                        state&=~(COMMENT_D3|COMMENT_D4);
+                        if((state&IN_COMMENT)!=IN_COMMENT) state&=~IN_COMMENT; // false alarm, it's not actually a comment
+                        baos.write(c);
+                }
+            } else { // Normal Tag Processing loop
+                switch(c) {
+                    case '?': 
+                        switch(state & (QUESTION_F|QUESTION)) {  // Validate the state of Doc tag... <?xml ... ?>
+                            case QUESTION_F:
+                                state |= DOC_TYPE;
+                                state &= ~QUESTION_F;
+                                break;
+                            case 0:
+                                state |=QUESTION_F;
+                                break;
+                            default:
+                                throw new IOException("Bad character [?] at " + count);
+                        }
+                        break;
+                    case '!':
+                        if(last=='<') { 
+                            state|=COMMENT|COMMENT_E; // likely a comment, continue processing in Comment Loop
+                        }
+                        baos.write(c);
+                        break;
+                    case '/':
+                        state|=(last=='<'?END_TAG:(END_TAG|START_TAG));  // end tag indicator </xxx>, ,or both <xxx/>
+                        break;
+                    case ':':
+                        prefix=baos.toString(); // prefix indicator
+                        baos.reset();
+                        break;
+                    case '=':                    // used in Attributes
+                        name=baos.toString();
+                        baos.reset();
+                        state|=VALUE;
+                        break;
+                    case '>': // end the tag, which causes end of this subprocess as well as formulation of the found data
+                        go = false;
+                        // passthrough on purpose
+                    case ' ':
+                    case '\t':
+                    case '\n': // white space indicates change in internal tag state, ex between name and between attributes
+                        if((state&VALUE)==VALUE) {
+                            value = baos.toString();    // we're in VALUE state, add characters to Value
+                        } else if(name==null) {
+                            name = baos.toString();        // we're in Name state (default) add characters to Name
+                        }
+                        baos.reset();                    // we've assigned chars, reset buffer
+                        if(name!=null) {                // Name is not null, there's a tag in the offing here...
+                            Tag t = new Tag(prefix,name,value);
+                            if(tag==null) {                // Set as the tag to return, if not exists
+                                tag = t;
+                            } else {                    // if we already have a Tag, then we'll treat this one as an attribute
+                                tag.add(t);
+                            }
+                        }
+                        prefix=name=value=null;            // reset these values in case we loop for attributes.
+                        break;
+                    case '\'':                            // is the character one of two kinds of quote?
+                    case '"':
+                        if(last!='\\') {
+                            quote=c;
+                            break;
+                        }
+                        // Fallthrough ok
+                    default:
+                        baos.write(c);                    // write any unprocessed bytes into buffer
+                        
+                }
+            }
+            last = c;
+        }
+        int type = state&(DOC_TYPE|COMMENT|END_TAG|START_TAG); // get just the Tag states and turn into Type for Tag
+        if(type==0) {
+            type=START_TAG;
+        }
+        if(tag!=null) {
+            tag.state|=type;    // add the appropriate Tag States
+        }
+        return tag;
+    }
 
-       /**
-        * getNSS
-        
-        * If the tag contains some Namespace attributes, create a new nss from the passed in one, copy all into it, then add
-        * This provides Scoping behavior
-        
-        * if Nss is null in the first place, create an new nss, so we don't have to deal with null Maps.
-        
-        * @param nss
-        * @param t
-        * @return
-        */
-       private Map<String, String> getNss(Map<String, String> nss, Tag t) {
-               Map<String,String> newnss = null;
-               if(t.attribs!=null) {
-                       for(Tag tag : t.attribs) {
-                               if("xmlns".equals(tag.prefix)) {
-                                       if(newnss==null) {
-                                               newnss = new HashMap<>();
-                                               if(nss!=null)newnss.putAll(nss);
-                                       }
-                                       newnss.put(tag.name, tag.value);
-                               }
-                       }
-               }
-               //return newnss==null?(nss==null?new HashMap<String,String>():nss):newnss;
-               if(newnss==null) {
-                       if(nss==null) {
-                               newnss = new HashMap<>();
-                       } else {
-                               newnss = nss;
-                       }
-               }
-               return newnss;
-       }
+    /**
+     * getNSS
+     * 
+     * If the tag contains some Namespace attributes, create a new nss from the passed in one, copy all into it, then add
+     * This provides Scoping behavior
+     * 
+     * if Nss is null in the first place, create an new nss, so we don't have to deal with null Maps.
+     * 
+     * @param nss
+     * @param t
+     * @return
+     */
+    private Map<String, String> getNss(Map<String, String> nss, Tag t) {
+        Map<String,String> newnss = null;
+        if(t.attribs!=null) {
+            for(Tag tag : t.attribs) {
+                if("xmlns".equals(tag.prefix)) {
+                    if(newnss==null) {
+                        newnss = new HashMap<>();
+                        if(nss!=null)newnss.putAll(nss);
+                    }
+                    newnss.put(tag.name, tag.value);
+                }
+            }
+        }
+        //return newnss==null?(nss==null?new HashMap<String,String>():nss):newnss;
+        if(newnss==null) {
+            if(nss==null) {
+                newnss = new HashMap<>();
+            } else {
+                newnss = nss;
+            }
+        }
+        return newnss;
+    }
 
-       /**
-        * The result of the parseTag method
-        
-        * Data is split up into prefix, name and value portions. "Tags" with Values that are inside a Tag are known in XLM
-        * as Attributes.  
-        
-        * @author Jonathan
-        *
-        */
-       public class Tag {
-               public int state;
-               public String prefix,name,value;
-               public List<Tag> attribs;
+    /**
+     * The result of the parseTag method
+     * 
+     * Data is split up into prefix, name and value portions. "Tags" with Values that are inside a Tag are known in XLM
+     * as Attributes.  
+     * 
+     * @author Jonathan
+     *
+     */
+    public class Tag {
+        public int state;
+        public String prefix,name,value;
+        public List<Tag> attribs;
 
-               public Tag(String prefix, String name, String value) {
-                       this.prefix = prefix;
-                       this.name = name;
-                       this.value = value;
-                       attribs = null;  
-               }
+        public Tag(String prefix, String name, String value) {
+            this.prefix = prefix;
+            this.name = name;
+            this.value = value;
+            attribs = null;  
+        }
 
-               /**
-                * add an attribute
-                * Not all tags need attributes... lazy instantiate to save time and memory
-                * @param tag
-                */
-               public void add(Tag attrib) {
-                       if(attribs == null) {
-                               attribs = new ArrayList<>();
-                       }
-                       attribs.add(attrib);
-               }
-               
-               public String toString() {
-                       StringBuffer sb = new StringBuffer();
-                       if(prefix!=null) {
-                               sb.append(prefix);
-                               sb.append(':');
-                       }
-                       sb.append(name==null?"!!ERROR!!":name);
+        /**
+         * add an attribute
+         * Not all tags need attributes... lazy instantiate to save time and memory
+         * @param tag
+         */
+        public void add(Tag attrib) {
+            if(attribs == null) {
+                attribs = new ArrayList<>();
+            }
+            attribs.add(attrib);
+        }
+        
+        public String toString() {
+            StringBuffer sb = new StringBuffer();
+            if(prefix!=null) {
+                sb.append(prefix);
+                sb.append(':');
+            }
+            sb.append(name==null?"!!ERROR!!":name);
 
-                       char quote = ((state&DOC_TYPE)==DOC_TYPE)?'\'':'"';
-                       if(value!=null) {
-                               sb.append('=');
-                               sb.append(quote);
-                               sb.append(value);
-                               sb.append(quote);
-                       }
-                       return sb.toString();
-               }
-       }
+            char quote = ((state&DOC_TYPE)==DOC_TYPE)?'\'':'"';
+            if(value!=null) {
+                sb.append('=');
+                sb.append(quote);
+                sb.append(value);
+                sb.append(quote);
+            }
+            return sb.toString();
+        }
+    }
 
 }