الحصول على عقدة XSLT الحالية، منسق كاستعلام XPath؟

StackOverflow https://stackoverflow.com/questions/1496434

  •  19-09-2019
  •  | 
  •  

سؤال

لدي كتلة التالية من التعليمات البرمجية التي تحصل على اسم العقد أسفل الشجرة، مثل هذا:

section/page/subPage

ولكن أود أن أكون قادرا على إلقاء الاتجاه إلى ما يلي (ما عليك سوى صنعه):

section[@id='someId']/page/subPage[@user='UserA']/@title

لقد وجدت التعليمات البرمجية التالية من أحد مشاركات Stackoverflow:


<xsl:attribute name="path">
  <xsl:for-each select="ancestor-or-self::*">
    <xsl:if test="name() != 'root'">
      <xsl:value-of select="name()">
        <xsl:if test="not(position()=last())">
          <xsl:text>/</xsl:text>
        </xsl:if>
      </xsl:value-of>
    </xsl:if>
  </xsl:for-each>
</xsl:attribute>

مما يعطيني المسار المستقيم، ولكن أود تشغيل المزيد من المنطق على ذلك لجعله، لذلك تضمنت الأيدي (أو السمة ذات الصلة)، وربما بعض الأشياء التي لا أستطيع التفكير فيها في الوقت الحالي.

ما هي أفضل طريقة للقيام بذلك؟

لقد راجعت في وظائف Exslt، والتي قد تعمل، ولكن ربما تكون رفاقا قد حلت هذه المشكلة بالفعل بطريقة أفضل.

أيه أفكار؟

أنا أستخدم NOKOGIRI ل Ruby's Nokogiri لتحليل XML / XSLT إذا كان ذلك يساعد.

شكرا جزيلا، انس

هل كانت مفيدة؟

المحلول

هذا الحل يفعل ما تريد:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" />

  <xsl:template match="/">
    <root>
      <xsl:attribute name="path">
        <xsl:apply-templates select="(//@title)[1]" mode="make-path" />
      </xsl:attribute>
    </root>
  </xsl:template>

  <xsl:template match="*|@*" mode="make-path">
    <xsl:apply-templates select="parent::*" mode="make-path" />
    <xsl:text>/</xsl:text>
    <xsl:apply-templates select="." mode="make-name" />
    <xsl:choose>
      <xsl:when test="self::section">
        <xsl:apply-templates select="@id" mode="make-predicate" />
      </xsl:when>
      <xsl:when test="self::subPage">
        <xsl:apply-templates select="@user" mode="make-predicate" />
      </xsl:when>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="*|@*" mode="make-predicate">
    <xsl:text>[</xsl:text>
    <xsl:apply-templates select="." mode="make-name" />
    <xsl:text> = '</xsl:text>
    <xsl:value-of select="." />
    <xsl:text>']</xsl:text>
  </xsl:template>

  <xsl:template match="*" mode="make-name">
    <xsl:value-of select="name()" />
  </xsl:template>

  <xsl:template match="@*" mode="make-name">
    <xsl:text>@</xsl:text>
    <xsl:value-of select="name()" />
  </xsl:template>

</xsl:stylesheet>

عند تطبيقها على

<section id="someId">
  <page>
    <subPage user="UserA" title="test" />
    <subPage user="UserB" title="blah" />
  </page>
  <page>
    <subPage user="UserC" title="fooh" />
  </page>
</section>

لقد حصلت:

<root path="/section[@id = 'someId']/page/subPage[@user = 'UserA']/@title" />

ال <xsl:choose> هي بقعة شكلي (إضافة أكبر عدد ممكن <xsl:when>S كما تريد):

<!-- test for element name -->
<xsl:when test="self::section">
  <!-- make predicates out of selected attributes -->
  <xsl:apply-templates select="@id" mode="make-predicate" />
</xsl:when>

من الممكن أيضا:

<xsl:when test="self::section">
  <xsl:apply-templates select="@name|@category|subElement" mode="make-predicate" />
</xsl:when>

مما يؤدي إلى

<root path="/section[@name = 'someName'][@category = 'somecat'][subElement = 'xyz']/..." />

المشكلة الوحيدة التي أراها هي مع قيم مسند تحتوي على علامات اقتباس واحدة. كانوا يكسرون xpath.

نصائح أخرى

لكل عقدة سلف، يمكنك حلقة على جميع السمات مع XSL بسيطة: لكل منها

<xsl:for-each select="@*">

يمكنك بعد ذلك استخدام السمات لبناء سلسلة XPath

<xsl:for-each select="ancestor-or-self::*">
   <xsl:if test="name() != 'root'">
      <xsl:value-of select="name()"/>
      <xsl:if test="@*">
         <xsl:text>[</xsl:text>
         <xsl:for-each select="@*">
            <xsl:text>@</xsl:text>
            <xsl:value-of select="name()"/>
            <xsl:text>='</xsl:text>
            <xsl:value-of select="."/>
            <xsl:text>'</xsl:text>
            <xsl:if test="not(position()=last())">
               <xsl:text> and </xsl:text>
            </xsl:if>
         </xsl:for-each>
         <xsl:text>]</xsl:text>
      </xsl:if>
      <xsl:if test="not(position()=last())">
         <xsl:text>/</xsl:text>
      </xsl:if>
   </xsl:if>
</xsl:for-each>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top