Intensivo de Namespaces
=======================

Como um dialeto XML, o SVG tem *namespace*. É importante entender o conceito de *namespaces* e como eles são usados se você planeja criar seu próprio conteúdo em SVG. Versões de visualizadores SVG prévias ao lançamento do Firefox 1.5 infelizmente deu pouca atenção aos *namespaces* mas eles são essenciais para dialetos multi-XML suportando agentes de usuários como navegadores baseados em Gecko que devem ser muito rigorosos. Tome um tempo para entender *namespaces* agora e irá te privar de muita dor de cabeça no futuro.

### Experiência

Tem sido uma longa meta do W3C para fazer possível para diferentes tipos de conteúdo baseado em XML ser misturado no mesmo arquivo XML. Por exemplo, SVG e MathML podem ser incorporados diretamente em um documento cientificamente baseado em XHTML. Ser apto de misturar tipos de conteúdo como este tem muitas vantagens, mas também requeriu problemas reais para serem resolvidos.

Naturalmente, cada dialeto XML define o significado de um nome de tag de marcação descrito em sua especificação. O problema em misturar conteúdo de diferentes dialetos XML em um único documento XML é que as tags definidas por um dialeto podem ter o mesmo nome que as tags definidas por outro. Por exemplo, ambos XHTML e SVG tem uma tag `<title>`. Como o software deveria distinguir entre os dois? Na verdade, como o software conta quando o conteúdo XML é algo que ele conhece sobre, e não somente um arquivo XML sem significado contendo nomes de tags arbitrárias desconhecidas para ele?

Contrário à opinição popular, a resposta para esta pergunta não é "ele pode dizer pela declaração `DOCTYPE`". DTD's não foram feitos com conteúdo misto levado em consideração, e tentativas passadas de criar DTD's de conteúdo misto são hoje consideradas de terem falhado. O XML, e alguns dialetos XML (incluindo SVG), não requerem uma declaração `DOCTYPE`, e SVG 1.2 nem terá um. O fato que declarações `DOCTYPE` (usualmente) combinam o conteúdo em arquivos de tipo de conteúdo únicos é uma mera coincidência. Os DTDs são somente para validação, não para identificação de conteúdo. Softwared que enganam e identificam conteúdo XML usando sua declaração `DOCTYPE` causam dano.

A resposta real para a pergunta é que um conteúdo XML conta para o software qual dialeto os nomes de tag pertencem ao dar "declarações de *namespaces*" para as tags.

### Declarando *namespaces*

O que estas declarações de *namespace* parecem, e onde elas vão? Aqui vai um exemplo curto.
```

<svg xmlns="https://www.w3.org/2000/svg">
  <!-- mais tags aqui -->
</svg>
```


A declaração de *namespace* é fornecida por um atributo `xmlns`. Este atributo diz que a tag `<svg>` e suas tags filhas pertencem a qualquer dialeto XML que tem o nome de *namespace* 'http://www.w3.org/2000/svg' que é, com certeza, SVG. Note a declaração de *namespace* somente precisa ser ser fornecida de uma vez em uma tag raiz. A declaração define o *namespace padrão*, então o software sabe que todas as tags descendentes de tags `<svg>` também pertencem ao mesmo *namespace*. Softwares conferem para ver se eles reconhecem o nome de *namespace* para determinar se eles sabem como lidar com a marcação.

Note que nomes de *namespace* são somente strings, então o fato que o nome de *namespace* SVG também parece com um URI não é importante. URI's são comumente usadas porque eles são únicos, a intenção não é para "linkar" em algum lugar. (Na verdade URI's são usadas tão frequentemente que o termo "URI de *namespace*" é comumente usado ao invés de "nome de namespace".)

#### Redeclarando o *namespace* padrão

Se todos os descendentes da tag raiz também são definidos para estarem presentes no *namespace* padrão, como você mistura conteúdo de outro *namespace*? Fácil. Você apenas redefine o *namespace* padrão. Aqui vai um exemplo simples.
```

<html xmlns="https://www.w3.org/1999/xhtml">
  <body>
    <!-- algumas tags XHTML aqui -->
    <svg xmlns="https://www.w3.org/2000/svg" width="300px" height="200px">
      <!-- algumas tags SVG aqui -->
    </svg>
    <!-- algumas tags XHTML aqui -->
  </body>
</html>
```


Neste exemplo o atributo `xmlns` na tag raíz `<html>` declara o *namespace* padrão para ser XHTML. Como um resultado, ela e todas as tags filhas são interpretadas pelo software como pertencente ao XHTML, exceto para a tag `<svg>`. A tag `<svg>` tem seu próprio atributo `xmlns`, e ao redeclarar o *namespace* padrão, isto conta para o software que a tag `<svg>` e suas descendentes (a menos que elas também redeclarem o *namespace* padrão) pertencem ao SVG.

Viu? *Namespaces* não são tão difíceis.

#### Declarando prefixos de *namespaces*

Dialetos XML não somente definem suas próprias tags, mas também seus próprios atributos. Por padrão, atributos não tem um *namespace*, e são conhecidos somente por ser únicos porque aparecem em um elemento que por si só tem um nome único. No entanto, algumas vezes é necessário definir atributos para que eles possam ser reusados em diferentes elementos e ainda sim serem considerados como sendo do mesmo atributo, independente do elemento com o qual eles são usados. Um exemplo muito bom disto é o atributo `href` definido pela especificação XLink. Este atributo é usado comumente por outros dialetos XML como um meio de conectar a recursos externos. Mas como você conta para o software qual dialeto o atributo pertence, neste caso XLink? Considere o exemplo seguinte.
```

<svg xmlns="https://www.w3.org/2000/svg"
     xmlns:xlink="https://www.w3.org/1999/xlink">
  <script xlink:href="o-script-mais-legal.js" type="text/ecmascript"/>
</svg>
```


Este exemplo tem o atributo de aparência bastante incomum `xmlns:xlink`. Como você pode ter adivinhado da primeira parte 'xmlns', esta é outra declaração de *namespace*. Contudo, ao invés de definir o *namespace* padrão, esta declaração de *namespace* define o namespace para alguma coisa chamada como "prefixo *namespace*". Neste caso, nós escolhemos usar o prefixo `xlink` (a segunda parte) uma vez que o prefixo será usado para contar ao software sobre os atributos que pertencem ao XLink.

Como seus nomes sugerem, prefixos de *namespace* são usados para prefixar nomes de atributos e nomes de tags. Isto é feito colocando o prefixo de *namespace* e dois pontos antes do nomes de atributo como mostrado na tag `<script>` no exemplo acima. Isto conta para o software que aquele atributo particular pertence ao *namespace* atribuído ao prefixo de *namespace* (XLink), e é um atribuído que pode ser usado com o mesmo significado em outras tags.

Note que é um erro de XML usar um prefixo que não foi ligado au um nome de *namespace*. A ligação criada pelo atributo `xmlns:xlink` no exemplo acima é absolutamente essencial se o atributo `xlink:href` não é para para causar um erro. Este atributo XLink é também frequentemente usado no SVG nas tags `<a>`, `<use>` e `<image>`, dentre outros, então é uma boa idéia sempre incluir a declaração XLink em seus documentos.

Aparte, é útil saber que prefixos podem também ser usados para names de tags. Isto conta para o software que aquela tag em particular (não a tag filha) pertence ao *namespace* ligado ao prefixo. Saber disso irá te poupar de confusão se você se deparar com uma marcação como a do exemplo seguinte:
```

<html xmlns="https://www.w3.org/1999/xhtml"
      xmlns:svg="https://www.w3.org/2000/svg">
  <body>
    <h1>SVG incorporado inline no XHTML</h1>
    <svg:svg width="300px" height="200px">
      <svg:circle cx="150" cy="100" r="50" fill="#ff0000"/>
    </svg:svg>
  </body>
</html>
```


Note que pelo prefixo de *namespace* ser usado para a tag `<svg:svg>` e seu filho `<svg:circle>`, não foi necessário redeclarar o *namespace* padrão. Em geral, é melhor redeclarar o *namespace* padrão ao invés de prefixar muitas tags desta forma.

### *Scripting* em XML com *namespaces*

*Namespaces* não afetam somente a marcação, mas também o *scripting*. Se você escreve scripts para XML com *namespace*, como SVG, continue lendo.

A recomendação DOM Level 1 foi criado antes da recomendação *original Namespaces in XML* ser lançada; assim sendo, DOM1 não está ciente de *namespaces*. Isto causa problemas para XML com namespaces, como SVG. Para resolver estes problemas, a recomendação DOM Level 2 Core adicionou equivalentes cientes do *namespace* de todos os métodos aplicáveis do DOM Nível 1. Quando estiver *scripting* em SVG, é *importante usar os métodos cientes de namespace*. A tabela abaixo lista os métodos DOM1 que não devem ser usados em SVG, junto com seus equivalentes em DOM2 que devem ser usados ao invés.

| DOM1 (não use) | DOM2 (use estes!) |
| --- | --- |
| createAttribute | createAttributeNS |
| createElement | createElementNS |
| getAttributeNode | getAttributeNodeNS |
| getAttribute | getAttributeNS |
| getElementsByTagName | getElementsByTagNameNS (também added to Element) |
| getNamedItem | getNamedItemNS |
| hasAttribute | hasAttributeNS |
| removeAttribute | removeAttributeNS |
| removeNamedItem | removeNamedItemNS |
| setAttribute | setAttributeNS |
| setAttributeNode | setAttributeNodeNS |
| setNamedItem | setNamedItemNS |

O primeiro argumento para todos os métodos cientes de *namespace* em DOM2 devem ser nomes de *namespace* (também conhecidos como *namespace* URI) do elemento ou atributo em questão. Para **elementos** SVG isto é 'http://www.w3.org/2000/svg'. Contudo, note cuidadosamente: as recomendações *Namespaces in XML 1.1* declara que o nome de *namespace* para atributos sem um prefixo não tem um valor. Em outras palavras, states that the *namespace* name for attributes without a prefix does not have a value. In other words, embora os atributos pertencem ao namespace da tag, você não usa o nome de namespace da tag. Em vez disso, **você deve usar nulo como nome de *namespace* para atributos não qualificados(sem prefixos)**. Então, para criar um *elemento* SVG `rect` usando `document.createElementNS()`, você deve escrever:


```javascript
document.createElementNS("https://www.w3.org/2000/svg", "rect");
```


Mas para recuperar o valor de atributo `x` em um elemento SVG `rect`, você deve escrever:


```javascript
rect.getAttributeNS(null, "x");
```


Note que isto não é o caso para atributos *com* um prefixo de *namespace* (atributos que não pertencem ao mesmo dialeto XML como a tag). Atributos como o `xlink:href` requerem o nome de *namespace* que foi designado para aquele prefixo (`https://www.w3.org/1999/xlink` para XLink). Consequentemente para pegar o valor do atributo `xlink:href` de um elemento `<a>` em SVG você deveria escrever:


```javascript
elt.getAttributeNS("https://www.w3.org/1999/xlink", "href");
```


Para definir atributos que tem um *namespace*, é recomendado (mas não requerido) que você também inclua seus prefixos no segundo argumento para que o DOM possa, depois, ser facilmente convertido depois para XML (se, por exemplo você quer enviá-los de volta para o servidor). Por exemplo:


```javascript
elt.setAttributeNS(
  "https://www.w3.org/1999/xlink",
  "xlink:href",
  "otherdoc.svg",
);
```


Como um exemplo final, aqui está a demonstração de como você deveria criar um elemento `<image>` dinamicamente usando script:


```javascript
var SVG\_NS = "https://www.w3.org/2000/svg";
var XLink_NS = "https://www.w3.org/1999/xlink";
var image = document.createElementNS(SVG\_NS, "image");
image.setAttributeNS(null, "width", "100");
image.setAttributeNS(null, "height", "100");
image.setAttributeNS(XLink_NS, "xlink:href", "flower.png");
```

### Conclusão

Tenha certeza que você sempre declara os *namespaces* que você usa em seus arquivos XML. Se você não usar, softwares como Firefox não reconhecerão seus conteúdos e irão simplesmente mostrar a marcação XML ou informar o usuário que há um erro no XML. É uma boa idéia usar um template que inclui todas as declarações de *namespace* comumente usadas ao criar novos arquivos SVG. Se você não tem um ainda, faça um começando com o seguinte código:
```

<svg xmlns="https://www.w3.org/2000/svg"
     xmlns:xlink="https://www.w3.org/1999/xlink">
</svg>
```


Mesmo que você não use todos aqueles *namespaces* em um documento, não há dano ao incluir declarações de *namespace*. Isto pode te privar de alguns erros irritantes se você acabar adicionando conteúdo de um dos *namespaces* não usados em datas posteriores.

### Um exemplo completo

Para um exemplo completo, veja *SVG: Namespaces Crash Course: Example (en-US)*.