2009-06-04 19 views
24

XSLT'de, bir öğeyi işlerken XML belgesinde nerede olduğunuzu belirlemenin bir yolu var mı?XSLT'deki geçerli eleman yolunu nasıl çıkış yaptınız?

Örnek: Bağlam Eleman "Ele111" ise aşağıdaki XML Doktor Parçası ... XSLT'de

<Doc> 
    <Ele1> 
    <Ele11> 
     <Ele111> 
     </Ele111> 
    </Ele11> 
    </Ele1> 
    <Ele2> 
    </Ele2> 
</Doc> 

göz önüne alındığında,, nasıl çıkışa XSLT tam yolunu alabilirim? Çıkmasını istiyorum: "/ Doc/Ele1/Ele11/Ele111".

Bu sorunun bağlamı: Ben (jenerik özyinelemeye kullanarak) etraflıca çekmesini istediğiniz çok büyük, çok derin bir belge var ve belirli bir özelliği olan bir öğe bulursanız, ben buldum nerede olduğunu bilmek istiyorum . Şu anki yol boyunca ilerlerken taşıyabileceğimi sanıyorum, ama XSLT/XPath'in bilmesi gerektiğini düşünürdüm.

cevap

6

Bunun, XPath üzerinde yerleşik olduğunu düşünmeyin, muhtemelen bu örneği temel aldığım bir here gibi yinelenen bir şablona ihtiyacınız vardır. Bir XML belgesindeki her öğeyi yürüyecek ve o öğeye giden yolu, tanımladığınıza benzer bir stilde çıkacak.

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     xmlns:xs="http://www.w3.org/2001/XMLSchema" 
     exclude-result-prefixes="xs" 
     version="2.0"> 

    <xsl:template match="/"> 
     <paths> 
      <xsl:apply-templates/> 
     </paths> 
    </xsl:template> 

    <xsl:template match="//*"> 
     <path> 
     <xsl:for-each select="ancestor-or-self::*"> 
      <xsl:call-template name="print-step"/> 
     </xsl:for-each> 
     </path> 
     <xsl:apply-templates select="*"/> 
    </xsl:template> 

    <xsl:template name="print-step"> 
     <xsl:text>/</xsl:text> 
     <xsl:value-of select="name()"/> 
     <xsl:text>[</xsl:text> 
     <xsl:value-of select="1+count(preceding-sibling::*)"/> 
     <xsl:text>]</xsl:text> 
    </xsl:template> 

</xsl:stylesheet> 

Birkaç sorun var; Bu ağaç göz önünde bulundurun:

<root> 
    <child/> 
    <child/> 
</root> 

İki çocuk düğümleri arasındaki farkı nasıl söylersiniz? Yani, öğe diziniz, çocuğunuz 1 ve çocuk [2] 'ye bazı endekslere ihtiyacınız var.

3

Hepiniz ebeveyne ve dedesi yürümeye atasıXPath Axes kullanabilirsiniz.

<xsl:for-each select="ancestor::*">... 
3

Ben kullanmakta olduğunuz XSLT işlemci emin değilim, ama Sakson ise, uzatma fonksiyonunu path() kullanabilirsiniz. Diğer işlemciler aynı işlevselliğe sahip olabilir.

20

Geçerli kabul edilen yanıt yanlış yollar döndürecektir. Örneğin, OP örneği XML'deki Ele2 öğesi /Doc[1]/Ele2[2] yolunu döndürür. /Doc[1]/Ele2[1] olmalıdır.

<xsl:template name="genPath"> 
    <xsl:param name="prevPath"/> 
    <xsl:variable name="currPath" select="concat('/',name(),'[', 
     count(preceding-sibling::*[name() = name(current())])+1,']',$prevPath)"/> 
    <xsl:for-each select="parent::*"> 
     <xsl:call-template name="genPath"> 
     <xsl:with-param name="prevPath" select="$currPath"/> 
     </xsl:call-template> 
    </xsl:for-each> 
    <xsl:if test="not(parent::*)"> 
     <xsl:value-of select="$currPath"/>  
    </xsl:if> 
    </xsl:template> 

İşte bütün unsurları bir path niteliği katacak bir örnek:

İşte doğru yolları döndüren benzer bir XSLT 1.0 taslak.

XML giriş

<Doc> 
    <Ele1> 
    <Ele11> 
     <Ele111> 
     <foo/> 
     <foo/> 
     <bar/> 
     <foo/> 
     <foo/> 
     <bar/> 
     <bar/> 
     </Ele111> 
    </Ele11> 
    </Ele1> 
    <Ele2/> 
</Doc> 

XSLT XML Çıktı

İşte
<Doc path="/Doc[1]"> 
    <Ele1 path="/Doc[1]/Ele1[1]"> 
     <Ele11 path="/Doc[1]/Ele1[1]/Ele11[1]"> 
     <Ele111 path="/Doc[1]/Ele1[1]/Ele11[1]/Ele111[1]"> 
      <foo path="/Doc[1]/Ele1[1]/Ele11[1]/Ele111[1]/foo[1]"/> 
      <foo path="/Doc[1]/Ele1[1]/Ele11[1]/Ele111[1]/foo[2]"/> 
      <bar path="/Doc[1]/Ele1[1]/Ele11[1]/Ele111[1]/bar[1]"/> 
      <foo path="/Doc[1]/Ele1[1]/Ele11[1]/Ele111[1]/foo[3]"/> 
      <foo path="/Doc[1]/Ele1[1]/Ele11[1]/Ele111[1]/foo[4]"/> 
      <bar path="/Doc[1]/Ele1[1]/Ele11[1]/Ele111[1]/bar[2]"/> 
      <bar path="/Doc[1]/Ele1[1]/Ele11[1]/Ele111[1]/bar[3]"/> 
     </Ele111> 
     </Ele11> 
    </Ele1> 
    <Ele2 path="/Doc[1]/Ele2[1]"/> 
</Doc> 

başka bir sürümünü var

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="text()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*"> 
    <xsl:copy> 
     <xsl:attribute name="path"> 
     <xsl:call-template name="genPath"/> 
     </xsl:attribute> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy>  
    </xsl:template> 

    <xsl:template name="genPath"> 
    <xsl:param name="prevPath"/> 
    <xsl:variable name="currPath" select="concat('/',name(),'[', 
     count(preceding-sibling::*[name() = name(current())])+1,']',$prevPath)"/> 
    <xsl:for-each select="parent::*"> 
     <xsl:call-template name="genPath"> 
     <xsl:with-param name="prevPath" select="$currPath"/> 
     </xsl:call-template> 
    </xsl:for-each> 
    <xsl:if test="not(parent::*)"> 
     <xsl:value-of select="$currPath"/>  
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

1,0

Bu sadece gerekli olduğunda konumsal yüklemi çıkarır. Bu örnek, yalnızca bir özellik eklemenin yerine yolun çıkmasıyla da farklıdır.XSLT ve XmlPrime 4 version="3.0" ile Saxon 9.8 (tüm sürümler) ya da Saxon 9.7 tarafından desteklenen

/Doc 
/Doc/Ele1 
/Doc/Ele1/Ele11 
/Doc/Ele1/Ele11/Ele111 
/Doc/Ele1/Ele11/Ele111/foo[1] 
/Doc/Ele1/Ele11/Ele111/foo[2] 
/Doc/Ele1/Ele11/Ele111/bar[1] 
/Doc/Ele1/Ele11/Ele111/foo[3] 
/Doc/Ele1/Ele11/Ele111/foo[4] 
/Doc/Ele1/Ele11/Ele111/bar[2] 
/Doc/Ele1/Ele11/Ele111/bar[3] 
/Doc/Ele2 
+0

+1. –

1

XPath'ın 3.0 yana (--xt30 kullanılarak): Yukarıdaki girişi, bu biçim sayfası çıkışları kullanarak

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="text()"/> 

    <xsl:template match="*"> 
     <xsl:for-each select="ancestor-or-self::*"> 
      <xsl:value-of select="concat('/',local-name())"/> 
      <!--Predicate is only output when needed.--> 
      <xsl:if test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]"> 
       <xsl:value-of select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')"/> 
      </xsl:if> 
     </xsl:for-each> 
     <xsl:text>&#xA;</xsl:text> 
     <xsl:apply-templates select="node()"/> 
    </xsl:template> 

</xsl:stylesheet> 

hem Altova 2017 bültenleri (version="3.0" stil kullanılarak) orada yerleşik path fonksiyonu (https://www.w3.org/TR/xpath-functions-30/#func-path, https://www.w3.org/TR/xpath-functions-31/#func-path)

<?xml version="1.0" encoding="UTF-8"?> 
<Doc> 
    <Ele1> 
     <Ele11> 
      <Ele111> 
       <foo/> 
       <foo/> 
       <bar/> 
       <foo/> 
       <foo/> 
       <bar/> 
       <bar/> 
      </Ele111> 
     </Ele11> 
    </Ele1> 
    <Ele2/> 
</Doc> 
gibi bir giriş için olan

ve

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" 
    exclude-result-prefixes="xs math" 
    version="3.0"> 

    <xsl:output method="text"/> 

    <xsl:template match="/"> 
     <xsl:value-of select="//*/path()" separator="&#10;"/> 
    </xsl:template> 

</xsl:stylesheet> 

gibi bir biçim sayfası çıkışı, el yapımı girişimi olarak ad alanlarının olmaması durumunda kompakt değil ama biçimi de (avantajı bu çıkış

/Q{}Doc[1] 
/Q{}Doc[1]/Q{}Ele1[1] 
/Q{}Doc[1]/Q{}Ele1[1]/Q{}Ele11[1] 
/Q{}Doc[1]/Q{}Ele1[1]/Q{}Ele11[1]/Q{}Ele111[1] 
/Q{}Doc[1]/Q{}Ele1[1]/Q{}Ele11[1]/Q{}Ele111[1]/Q{}foo[1] 
/Q{}Doc[1]/Q{}Ele1[1]/Q{}Ele11[1]/Q{}Ele111[1]/Q{}foo[2] 
/Q{}Doc[1]/Q{}Ele1[1]/Q{}Ele11[1]/Q{}Ele111[1]/Q{}bar[1] 
/Q{}Doc[1]/Q{}Ele1[1]/Q{}Ele11[1]/Q{}Ele111[1]/Q{}foo[3] 
/Q{}Doc[1]/Q{}Ele1[1]/Q{}Ele11[1]/Q{}Ele111[1]/Q{}foo[4] 
/Q{}Doc[1]/Q{}Ele1[1]/Q{}Ele11[1]/Q{}Ele111[1]/Q{}bar[2] 
/Q{}Doc[1]/Q{}Ele1[1]/Q{}Ele11[1]/Q{}Ele111[1]/Q{}bar[3] 
/Q{}Doc[1]/Q{}Ele2[1] 

verir Ad alanlarının kullanılmasına izin vermek ve yol ifadesinin kullanıcısını değerlendirmek için herhangi bir ad alanı bağlaması oluşturmak için yol ifadesinin kullanıcısını gerektirmeyen döndürülen yol için bir biçim elde etmek için en az verilen XPath 3.0 veya 3.1 desteği). XPATH ifadeleri için

+0

Güzel. Belirli bir bağlamda dağınık olan ad alanından kurtulmak için replace() işlevini kullandım. İsim alanı bilgilerinin olmasına rağmen memnunum. – David

İlgili konular