Nasıl dize geçerli bir XML öğesi adı olup olmadığını kontrol etmek için?

8 Cevap php

Ben bir dize iyi bir XML elemanı isim olmak doğrular PHP bir regex ya da bir işlev gerekir.

Form W3Schools:

XML elements must follow these naming rules:

  1. İsimler harf, sayı ve diğer karakterleri içerebilir
  2. İsimler bir sayı veya noktalama karakteri ile başlayamaz
  3. İsimler harfler xml (ya da XML veya Xml, vb) ile başlayamaz
  4. İsimler boşluk içeremez

Ben kurallara 1,2 ve 4 için kontrol edecek bir temel regex yazabilirsiniz, ama buna izin tüm noktalama için hesap değil ve 3. kural için hesap değil

\w[\w0-9-]

Friendly Update

İşte için daha güvenilir kaynak well-formed XML Element names:

İsimler ve Dizgecikler

NameStartChar   ::=
    ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] |
    [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | 
    [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | 
    [#x10000-#xEFFFF]

NameChar    ::=
    NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]

Name    ::=
    NameStartChar (NameChar)*

Ayrıca ayrı bir sigara dizgecikli kuralı belirtilir:

Dizesi, "xml" ile başlayan isimler, ya da maç herhangi bir dize ile (('X' | 'x') ('M' | 'm') ('L' | 'l')), standardizasyon için ayrılmıştır Bu veya bu şartnamenin gelecek sürümlerinde.

8 Cevap

Nasıl hakkında

/\A(?!XML)[a-z][\w0-9-]*/i

Kullanımı:

if (preg_match('/\A(?!XML)[a-z][\w0-9-]*/i', $subject)) {
    # valid name
} else {
    # invalid name
}

Açıklama:

\A  Beginning of the string
(?!XML)  Negative lookahead (assert that it is impossible to match "XML")
[a-z]  Match a non-digit, non-punctuation character
[\w0-9-]*  Match an arbitrary number of allowed characters
/i  make the whole thing case-insensitive

Eğer oluşturmak istiyorsanız valid XML, DOM Extension kullanın. Bu şekilde herhangi bir Regex hakkında rahatsız gerekmez. Bir DomElement için geçersiz bir ad koymak için çalışırsanız, bir hata alırsınız.

function isValidXmlName($name)
{
    try {
        new DOMElement($name);
        return TRUE;
    } catch(DOMException $e) {
        return FALSE;
    }
}

Bu verecek

var_dump( isValidXmlName('foo') );      // true   valid localName
var_dump( isValidXmlName(':foo') );     // true   valid localName
var_dump( isValidXmlName(':b:c') );     // true   valid localName
var_dump( isValidXmlName('b:c') );      // false  assumes QName

ve büyük olasılıkla yapmak istediğiniz şey için yeterince iyi.

Pedantic note 1

LocalName ve QName arasındaki ayrım dikkat edin. ext / dom adı oluşturulabilir nasıl kısıtlamaları ekler kolon önce bir önek, orada eğer bir isim alanlı elemanı kullanılarak varsayar. Teknik olarak, b çünkü: NameStartChar is part of NameChar b geçerli bir yerel isim olsa. Eğer bu dahil etmek istiyorsanız, için işlevini değiştirmek

function isValidXmlName($name)
{
    try {
        new DOMElement(
            $name,
            null,
            strpos($name, ':') >= 1 ? 'http://example.com' : null
        );
        return TRUE;
    } catch(DOMException $e) {
        return FALSE;
    }
}

Pedantic note 2

Unsurlar "xml" ile başlar unutmayın. W3Schools (kim W3C ile bağlı değildir) görünüşe göre bu bölümü yanlış var (wouldn't be the first time). Eğer gerçekten xml eklenti ile başlayan unsurları dışlamak istiyorsanız

if(stripos($name, 'xml') === 0) return false;

önce try/catch.

PHP'nin pcre fonksiyonlar üzerinden Adı doğrulama XML spesifikasyonu ile aerodinamik olduğu: Bu soru eski olduğunu rağmen şimdiye kadar cevapsız olmuştur.

XML'in tanımı en özelliklerde eleman isim hakkında oldukça açıktır (Extensible Markup Language (XML) 1.0 (Fifth Edition)):

[4]  NameStartChar  ::=   ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
[4a] NameChar       ::=   NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
[5]  Name           ::=   NameStartChar (NameChar)*

Bu gösterim, tek tırnaklı PHP string kelimesi kelimesine kopyalanmasına burada olduğu gibi, preg_match ile kullanılacak bir UTF-8 uyumlu düzenli ifade aktarılmamış olabilir:

'~^[:A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\x{2FF}\\x{370}-\\x{37D}\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}\\x{10000}-\\x{EFFFF}][:A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\x{2FF}\\x{370}-\\x{37D}\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}\\x{10000}-\\x{EFFFF}.\\-0-9\\xB7\\x{0300}-\\x{036F}\\x{203F}-\\x{2040}]*$~u'

Ya da bir daha okunabilir şekilde adlandırılmış alt şablon ile başka varyantı olarak:

'~
# XML 1.0 Name symbol PHP PCRE regex <http://www.w3.org/TR/REC-xml/#NT-Name>
(?(DEFINE)
    (?<NameStartChar> [:A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\x{2FF}\\x{370}-\\x{37D}\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}\\x{10000}-\\x{EFFFF}])
    (?<NameChar>      (?&NameStartChar) | [.\\-0-9\\xB7\\x{0300}-\\x{036F}\\x{203F}-\\x{2040}])
    (?<Name>          (?&NameStartChar) (?&NameChar)*)
)
^(?&Name)$
~ux'

Bu desen XML ad alanı doğrulama nedenlerle (örn. için bir test NCName için (ilk desen, ikinci bir iki görünüşlerine) dışlamak isteyebilirsiniz : kolon içerdiğini unutmayın ).

Kullanımı Örnek:

$name    = '::...';
$pattern = '~
# XML 1.0 Name symbol PHP PCRE regex <http://www.w3.org/TR/REC-xml/#NT-Name>
(?(DEFINE)
    (?<NameStartChar> [:A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\x{2FF}\\x{370}-\\x{37D}\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}\\x{10000}-\\x{EFFFF}])
    (?<NameChar>      (?&NameStartChar) | [.\\-0-9\\xB7\\x{0300}-\\x{036F}\\x{203F}-\\x{2040}])
    (?<Name>          (?&NameStartChar) (?&NameChar)*)
)
^(?&Name)$
~ux';

$valid = 1 === preg_match($pattern, $name); # bool(true)

XML (alt ya da büyük harflerle) ile başlayan bir eleman ismi mümkün olmayacağını söyleyerek doğru değildir. <XML/> mükemmel bir iyi biçimli XML ve XML mükemmel bir iyi biçimli eleman adıdır.

Bu tür isimler reserved for standardization (XML versiyonu yukarıda 1.0 ve üzeri) olan iyi oluşturulmuş eleman isimleri alt kümesi olan sadece budur. Bu (iyi-oluşturulmuş) elemanı adı bir dize karşılaştırma ile ayrılmış olup olmadığını test etmek kolaydır:

$reserved = $valid && 0 === stripos($name, 'xml'));

ya da alternatif başka bir düzenli ifade:

$reserved = $valid && 1 === preg_match('~^[Xx][Mm][Ll]~', $name);

Ayrılmış adlar için PHP's DOMDocument can not testi, en azından bunu yapmak için nasıl bir yol bilmiyorum ve ben çok arıyorum oldum.

Geçerli bir öğe adı böyle bir beyanı sağlanmıştır burada sorunun kapsamı dışında gibi görünüyor bir Unique Element Type Declaration hangi gerekiyor. Bu nedenle cevabı dikkat almaz. Bir eleman türü bildirimi orada olurdu, sadece tüm (harf duyarlı) isimleri bir beyaz liste karşı doğrulamak gerekir, bu yüzden basit bir harf duyarlı dize karşılaştırma olacaktır.


Excursion: What does DOMDocument Düzenli İfade için farklı mı?

Bir ile karşılaştırıldığında DOMDocument / DOMElement, geçerli bir öğe adı nitelendirir bazı farklılıklar vardır. DOM uzantısı doğrular ne daha az öngörülebilir hale karma mod çeşit olduğunu. Aşağıdaki gezi davranışı gösterir ve onu kontrol etmek için nasıl gösterir.

En $name almak ve bir öğe örneğini alalım:

$element = new DOMElement($name);

Sonuç değişir:

Yani ilk karakter karşılaştırma modu hakkında karar verir.

Bir düzenli ifade özel XML 1.0 Name simgesi burada, kontrol etmek için ne yazılır.

Bir kolon adını önek tarafından DOMElement ile aynı elde edebilirsiniz:

function isValidXmlName($name)
{

    try {
        new DOMElement(":$name");
        return TRUE;
    } catch (DOMException $e) {
        return FALSE;
    }
}

Açıkça QName Bu çevirerek elde edilebilir kontrol etmek için bir PrefixedName durumda öyle bir UnprefixedName:

function isValidXmlnsQname($qname)
{
    $prefixedName = (!strpos($qname, ':') ? 'prefix:' : '') . $qname;

    try {
        new DOMElement($prefixedName, NULL, 'uri:ns');
        return TRUE;
    } catch (DOMException $e) {
        return FALSE;
    }
}

Mef güzel cevap esinlenerek, ancak (başka türlü 'aaa BBB' gibi boşluk içeren XML isimleri kabul edilecektir) ve '$' biten

$validXmlName = (preg_match('/^(?!XML)[a-z][\w0-9-]*$/i', $subject) != 0);

Bu regex kullanın:

^_?(?!(xml|[_\d\W]))([\w.-]+)$

Bu, tüm dört puan maçlar ve unicode karakterleri verir.

Eğer DotNet çerçevesi kullanıyorsanız XmlConvert.VerifyName deneyin. Bu isim geçerli olup olmadığını size söyleyecektir, ya da aslında geçerli bir birine geçersiz bir ad dönüştürmek için XmlConvert.EncodeName kullanacak ...

Aşağıdaki ifade xml hariç geçerli unicode eleman isimlerini eşleşmesi gerekir. Başlatmak veya xml ile biten isimler hala izin verilecektir. Bu toscho en AON testi @ geçer. Ben bir regex çözemedim bir şey genişleticiler oldu. Xml öğe adı spec diyor ki:

[4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender

[5] Adı :: = (Letter | '_' | ':') (AdKark) *

Ama genişleticiler içeren bir unicode kategori ya da sınıf için açık bir tanım yoktur.

^[\p{L}_:][\p{N}\p{L}\p{Mc}.\-|:]*((?<!xml)|xml)$

This should give you roughly what you need [Assuming you are using Unicode]:
(Note: This is completely untested.)

[^\p{P}xX0-9][^mMlL\s]{2}[\w\p{P}0-9-]

\p{P} is the syntax for Unicode Punctuation marks PHP'nin düzenli ifade sözdizimi.