Выбор родительского / родительского узла на основе значения в дочернем узле - PullRequest
0 голосов
/ 10 августа 2010

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

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

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

Вот фрагмент 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, содержащая ключевое слово, которое она ищет, чтобы увидеть, существуют ли подстроки в параметре иглы, которые являются поисковыми словами, введенными пользователем, внутри параметра стога сена, который является значением элемента или атрибута, который пользователь ищет в публикации , Я сам не уверен в том, что именно происходит, но, похоже, это работает правильно.

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 будет смотреть только на первый элемент Attribute, когда ему нужно будет просмотреть все дочерние элементы в элементе CustomAttribute.

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

Спасибо.

Ответы [ 2 ]

0 голосов
/ 11 августа 2010

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

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

<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 в исходной переменной, и когда я нахожу совпадение, я вместо этого отправляю исходную переменную для рендера.

0 голосов
/ 10 августа 2010

Я думаю, что ту же задачу можно выполнить в 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>

Параметр Whit pKeywords значение по умолчанию установлено на «Черновик», вывод:

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...