2010-08-10 3 views
0

Моя компания производит публикацию, которая выводит текущий набор диаграмм клиентов, Вы можете искать публикации для диаграмм с заданным значением атрибута.Выбор родительского/предкового узла на основе значения в дочернем узле

Это работает, но только если значение содержится в первом узле атрибута.

Я и еще один человек пытались исправить это, чтобы он искал все атрибуты.

Вот фрагмент xsl, используемый для поиска атрибутов. Он ищет в Диаграмме Папки и Элементах Формы, чтобы видеть, содержит ли дочерний элемент Атрибута слово, введенное пользователем.

 <xsl:template name="testObject"> 
    <xsl:if test="(name() = 'Shape' and $includeShapes) or (name() = 'Folder' and $includeFolders) or (name() = 'Document' and $includeDocuments) or (name() = 'Diagram' and $includeDiagrams)"> 
     <xsl:variable name="objXMLLocation"> 
      <xsl:choose> 
       <xsl:when test="name() = 'Folder'"> 
        <xsl:value-of select="concat(@ID, '/folder.xml')" /> 
       </xsl:when> 
       <xsl:when test="name() = 'Document'"> 
        <xsl:value-of select="concat(@ID, '/document.xml')" /> 
       </xsl:when> 
       <xsl:when test="name() = 'Diagram'"> 
        <xsl:value-of select="concat(@ID, '/diagram.xml')" /> 
       </xsl:when> 
       <xsl:when test="name() = 'Shape'"> 
        <xsl:value-of select="concat(../../@ID, '/', ../../@ID, '_files/', @Source)" /> 
       </xsl:when> 
      </xsl:choose> 
     </xsl:variable> 

     <xsl:if test="js:fileExists($objXMLLocation)"> 
      <xsl:variable name="objXML" select="document($objXMLLocation)" /> 
      <xsl:choose> 
       <xsl:when test="$searchName"> 
        <xsl:if test="js:containsKeywords($objXML/*/Properties/RepositoryName, $searchKeywords)"> 
         <xsl:apply-templates mode="render" select="."> 
          <xsl:with-param name="fullXML" select="$objXML" /> 
         </xsl:apply-templates> 
        </xsl:if> 
       </xsl:when> 
       <xsl:when test="$searchDescription"> 
        <xsl:if test="js:containsKeywords($objXML/*/Properties/Description, $searchKeywords)"> 
         <xsl:apply-templates mode="render" select="."> 
          <xsl:with-param name="fullXML" select="$objXML" /> 
         </xsl:apply-templates> 
        </xsl:if> 
       </xsl:when> 
       <xsl:when test="$searchAttributes"> 
        <xsl:if test="name() != 'Folder'">      
        <xsl:if test="js:containsKeywords($objXML/*/CustomAttributes/Attribute/Value,$searchKeywords)"> 
         <xsl:apply-templates mode="render" select="."> 
          <xsl:with-param name="fullXML" select="$objXML" /> 
         </xsl:apply-templates> 
        </xsl:if> 
        </xsl:if> 
       </xsl:when> 
      </xsl:choose> 
     </xsl:if> 
    </xsl:if> 
</xsl:template> 

Вот функция Javascript containsKeyword это выглядит, чтобы увидеть, если подстроки в параметре иглы, которые являются поисковыми словами, введенных пользователем, существует внутри параметра стога, который является значением элемента или атрибута, которого пользователь поиск публикации для. Я сам не уверен, что происходит, но, похоже, работает правильно.

function containsKeywords(haystack, needles) { 
     var ks = needles[0].selectNodes('//K'); 
     var n; 
     if (haystack[0].firstChild) { 
      n = haystack[0].firstChild.nodeValue.toUpperCase(); 
     } else { 
      return 0; 
     } 
     for (var i = 0; i < ks.length; i++) { 
      if (n.indexOf(ks[i].firstChild.nodeValue) < 0) { 
       return 0; 
      } 
     } 
     return 1; 
    } 

Исследуется xml.

<Diagram ID="49ab6eb5-c51f-4e36-9495-869897ef0d0d"> 
    <CustomAttributes> 
    <Attribute> 
    <Name>Approval Status</Name> 
    <Description>Document/Diagram/Object Approval Status</Description> 
    <Value>Draft - Work in Progress</Value> 
    <Datatype>Text</Datatype> 
</Attribute> 
<Attribute> 
    <Name>Next Document Review Date</Name> 
    <Description>When is this document to be reviewed next?</Description> 
    <Value /> 
    <Datatype>Date</Datatype> 
</Attribute> 
<Attribute> 
    <Name>Stakeholder View</Name> 
    <Description>Select the Stakeholder View</Description> 
    <Value>PMO</Value> 
    <Datatype>Text</Datatype> 
</Attribute> 

Текущий XSL будет оказывать ссылку на диаграмме, если проект будет входить, как она существует в элементе Значение ребенка 1-го атрибута элемента. Но поиск PMO ничего не вернет.

Проблема заключается в том, что xsl будет рассматривать только первый элемент атрибута, когда ему нужно посмотреть на все дочерние элементы элемента CustomAttribute.

Мы попытались использовать для каждого из элементов Атрибута, с которыми нам приходилось сталкиваться с деревом xml, чтобы получить предка Diagram, чтобы он мог быть выбран для рендеринга.

Спасибо.

+0

Этот вопрос абсолютно неясен. Я не вижу, что делает XSLT-код (вы показываете только очень небольшую часть кода), и неясно, чего вы хотите достичь. Кроме того, неясно, имеет ли код JS какое-либо отношение к вашей проблеме или нет. Не ожидайте, что люди, которые будут контролировать и отвечать на вопросы xslt, будут хороши в JS, - поэтому, если JS важен, по крайней мере, объясните словами, что делает JS-код. Короче, пожалуйста, переработайте свой вопрос. –

+0

Я бы сказал, что ваша функция js: containsKeywords ($ objXML/*/CustomAttributes/Attribute/Value, $ searchKeywords) не работает так, как вы думаете, или, по крайней мере, это то, на что я бы посмотрел, но как Dimitre говорит, нет способа сказать, поскольку это не включено. – Woody

+0

Я добавил javascript обратно. Надеюсь, это упростит или поможет устранить возможные источники ошибок. – ywm

ответ

0

Я думаю, что та же задача может быть выполнена в XSLT. Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="CustomAttributes" name="search"> 
     <xsl:param name="pAttributes" select="Attribute/Value"/> 
     <xsl:param name="pKeywords" select="''"/> 
     <xsl:choose> 
      <xsl:when test="$pKeywords != ''"> 
       <xsl:call-template name="search"> 
        <xsl:with-param name="pAttributes" 
            select="$pAttributes 
                [contains(
                 concat(' ',.,' '), 
                 concat(' ', 
                   substring-before(
                    concat($pKeywords,' '), 
                    ' '), 
                   ' '))]"/> 
        <xsl:with-param name="pKeywords" select="substring-after($pKeywords,' ')"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <found> 
        <xsl:copy-of select="$pAttributes"/> 
       </found> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

При надлежащем входе:

<Diagram ID="49ab6eb5-c51f-4e36-9495-869897ef0d0d"> 
    <CustomAttributes> 
     <Attribute> 
      <Name>Approval Status</Name> 
      <Description>Document/Diagram/Object Approval Status</Description> 
      <Value>Draft - Work in Progress</Value> 
      <Datatype>Text</Datatype> 
     </Attribute> 
     <Attribute> 
      <Name>Next Document Review Date</Name> 
      <Description>When is this document to be reviewed next?</Description> 
      <Value /> 
      <Datatype>Date</Datatype> 
     </Attribute> 
     <Attribute> 
      <Name>Stakeholder View</Name> 
      <Description>Select the Stakeholder View</Description> 
      <Value>PMO</Value> 
      <Datatype>Text</Datatype> 
     </Attribute> 
    </CustomAttributes> 
</Diagram> 

Уит парам значение pKeywords по умолчанию установлено значение 'Проект', выход:

<found> 
    <Value>Draft - Work in Progress</Value> 
</found> 

Примечание: Когда парам pKeywords является не установлен или установлен в пустую строку '' выводит весь набор узлов в параметре pAttributes, s o вы можете подумать об этом шаблоне в качестве фильтра. Кроме того, вы можете отредактировать вывод, чтобы сделать его полезным для вашей логики, например: вы можете просто вывести тестовое значение для непустого pAttributes, объявить переменную с содержимым вызова этого шаблона, проверить строковое значение этой переменной и применяйте шаблоны так же, как в вашем фрагменте таблицы стилей.

+0

Как я могу вернуть корневой узел с помощью вашего кода? Диаграммы распространяются по отдельным XML-файлам, а xsl ищет каждый, а затем текущий XML-файл отправляется в шаблон рендеринга. – ywm

+0

@ywm: этот именованный шаблон представляет собой XSLT-реализацию вашей функции расширения (расширение медленное, механизм сценария загружается с каждым вызовом). Вы можете передать набор узлов для поиска (param 'pAttributes') и пробел в отдельном списке ключевых слов (param' pKeywords'). Вывод может быть просто фиктивной строкой для теста (как вы это делаете в 'test =" js: containsKeywords (... '), который вы« храните »в переменной. – 2010-08-11 13:16:23

0

Хорошо, я выяснил, в чем проблема.

Вот решение, которое я попробую и объясню, что происходит.

<xsl:when test="$searchDescription"> 
        <xsl:if test="js:containsKeywords($objXML/*/Properties/Description, $searchKeywords)"> 
         <xsl:apply-templates mode="render" select="."> 
          <xsl:with-param name="fullXML" select="$objXML" /> 
         </xsl:apply-templates> 
        </xsl:if> 
       </xsl:when> 
       <xsl:when test="$searchAttributes"> 
        <xsl:variable name="source" select="."></xsl:variable> 
        <xsl:if test="name() != 'Folder'"> 
         <xsl:for-each select="$objXML/*/CustomAttributes//Attribute"> 
          <xsl:if test="js:containsKeywords(./Value,$searchKeywords)"> 
           <xsl:apply-templates mode="render" select="$source"> 
            <xsl:with-param name="fullXML" select="$objXML" /> 
           </xsl:apply-templates> 
          </xsl:if> 
         </xsl:for-each> 
        </xsl:if> 
       </xsl:when> 

Этот фрагмент является частью шаблона, который применяется ко всем другим файлом Xml к тому, что ищется.

В поиске поиска, когда что-то обнаружено, в редакторе выбран узел публикации. Поскольку существует несколько узлов атрибутов, которые выполняют то же самое, что и поиск описания, поиск выполняется только по первому элементу атрибута. Таким образом, использование for-each будет проходить через все атрибуты, но в то же время изменяет контекст на поиск xml-файла.

Поэтому, чтобы отправить правильный бит в шаблон рендеринга, я сохранил контекст перед именем for-each в исходной переменной, и когда я нахожу совпадение, я отправляю исходную переменную в рендер.

Смежные вопросы