WedX - журнал о программировании и компьютерных науках

Как ограничить вывод шаблона одним значением при поиске с помощью key()

У меня есть руководство по деталям, состоящее из набора нескольких XML-файлов, сегментированных по разным группам деталей. Каждая группа деталей содержит несколько таблиц с информацией, относящейся к отдельным деталям, включая уникальный номер детали. Каждая отдельная часть содержится в виде одной строки в таблице. Я добавил в эти таблицы пустой столбец, который будет указывать, ограничена ли продажа детали значением «да» или «нет», когда я запускаю ее через свое преобразование.

Я написал преобразование XSLT, чтобы найти номер детали в файле поиска, сравнить его с номером детали в документе, который я обрабатываю, и, когда они совпадают, заполнить пустой столбец «да» или «нет» в зависимости от того, что указан в XML-документе поиска.

Каталожные номера уникальны. Однако некоторые детали используются с несколькими группами деталей. Хотя руководство по деталям состоит из нескольких файлов XML, файл поиска, который я использую, основан на спецификации. Итак, это один большой XML-документ, содержащий все части для каждой группы.

XML-документ, который я обрабатываю, выглядит так:

<reference>
    <title>Part Group A</title>
    <refbody>
        <section>
            <image href="partGroupA.svg"/>
        </section>
        <simpletable>
            <sthead>
                <stentry>Annotation</stentry>
                <stentry>Part Name</stentry>
                <stentry>Restricted?</stentry>
                <stentry>Part Description</stentry>
                <stentry>Part Number</stentry>
                <stentry>Quantity</stentry>
                <stentry>Comment</stentry>
            </sthead>
            <strow>
                <stentry translate="no" props="annotation">1</stentry>
                <stentry translate="no" props="part-name">SomePart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">SomePart</stentry>
                <stentry translate="no" props="part-number">1234567-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Some comment</stentry>
            </strow>
            <strow>
                <stentry translate="no" props="annotation">2</stentry>
                <stentry translate="no" props="part-name">AnotherPart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">AnotherPart</stentry>
                <stentry translate="no" props="part-number">2345678-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Another comment</stentry>
            </strow>
            ...
        </simpletable>
    </refbody>
</reference>

XML-документ поиска содержит следующее:

...
<strow>
  <stentry props="part-section">Part Group A</stentry>
  <stentry props="part-name">SomePart</stentry>
  <stentry props="part-number">1234567-00-A</stentry>
  <stentry props="part-restrict">Yes</stentry>
</strow>
<strow>
   <stentry props="part-section">Part Group A</stentry>
   <stentry props="part-name">AnotherPart</stentry>
   <stentry props="part-number">2345678-00-A</stentry>
   <stentry props="part-restrict">No</stentry>
</strow>
...
<strow>
  <stentry props="part-section">Part Group B</stentry>
  <stentry props="part-name">SomePart</stentry>
  <stentry props="part-number">1234567-00-A</stentry>
  <stentry props="part-restrict">No</stentry>
</strow>
...

Мое XSLT-преобразование выглядит так:

<xsl:output method="xml" encoding="UTF-8" indent="yes" doctype-system="reference.dtd" doctype-public="-//OASIS//DTD DITA Reference//EN"/>
<xsl:strip-space elements="*"/>

<xsl:key name="part-number" match="strow" use="stentry[@props='part-number']" />

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

<xsl:template match="stentry[@props='part-restrict']">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:variable name="matching-part" select="key('part-number', ../stentry[@props='part-number'], document('pm_restrict_redo-2.xml'))" />
        <xsl:choose>
            <xsl:when test="$matching-part">
                <xsl:value-of select="$matching-part/stentry[@props='part-restrict']"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:copy>
</xsl:template>

Это работает до определенного момента. Поскольку в некоторых случаях номер детали используется несколько раз в разных группах деталей (для разных систем, подсистем и т. д.) и несколько раз указывается в поиске спецификации, мое преобразование заканчивается выводом «да» или «нет» для каждого возникновение части. Результирующий XML выглядит следующим образом:

<strow>
        <stentry translate="no" props="annotation">1</stentry>
        <stentry translate="no" props="part-name">SomePart</stentry>
        <stentry translate="no" props="part-restrict">yes no</stentry>
        <stentry translate="yes" props="part-desc">SomePart</stentry>
        <stentry translate="no" props="part-number">1234567-00-A</stentry>
        <stentry translate="no" props="quantity">1</stentry>
        <stentry translate="yes" props="comment">Some comment</stentry>
</strow>

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

Любая помощь приветствуется.

11.04.2015

  • Способ получения значения, относящегося только к узлу контекста, ускользает от меня. Что же, является правильным контекстом? 11.04.2015
  • @ michael.hor257k Да, это часть проблемы, верно? Как сценарий должен знать правильный контекст? Для этого я пытался сузить правильный контекст, используя узел часть-раздел в файле поиска. Это, по крайней мере, сужает область действия до номеров деталей, которые являются только элементами определенной системы => подсистемы => группы деталей. Однако я еще не смог понять, как ограничить шаблон, выводящий этот конкретный набор узлов. 11.04.2015
  • Пожалуйста, отредактируйте вопрос и предоставьте желаемый результат. Также, пожалуйста, объясните правила, которые должно реализовывать преобразование. Без этой важной информации вопрос неоднозначен, и вы можете получить много разных ответов, ни один из которых не дает решения реальной проблемы. 11.04.2015
  • Я еще не смог понять, как ограничить шаблон, выводящий этот конкретный набор узлов. Вы не хотите ограничивать шаблон; вы хотите ограничить область применения ключа. Вместо того, чтобы позволить ему соответствовать любому элементу strow в любом месте документа поиска, вам нужно сузить шаблон соответствия, чтобы включить только узлы strow в определенной ветви документа. Я не могу посоветовать, как это сделать, потому что не вижу документа и не знаю, как он устроен. 11.04.2015
  • @DimitreNovatchev Я отредактировал сообщение и попытался более точно описать то, что я пытаюсь сделать. Пожалуйста, дайте мне знать, если я не смог ответить на ваш запрос. 12.04.2015
  • @JasonDavis, я не вижу ни одной группы частей в вашем исходном XML-документе, и поэтому невозможно найти решение, если эти данные не отображаются. Пожалуйста, предоставьте полный (но краткий) исходный XML-документ с полными данными. 12.04.2015
  • @ michael.hor257k Это имеет смысл, и я попытался сделать это, выполнив сопоставление с группой частей (раздел части в поиске). Однако я не мог прийти к конструкции, которая позволила бы мне это сделать. Я отредактировал свой пост, чтобы внести ясность. Итак, надеюсь, это даст больше понимания. 12.04.2015
  • @DimitreNovatchev Я отредактировал сообщение, чтобы привести более полный пример. Каждая группа деталей в руководстве по деталям представлена ​​одним XML. Группа деталей, с которой деталь связана в спецификации, представлена ​​узлами props=part-section. 12.04.2015
  • Вы должны сообщить нам, как бы вы сделали это вручную. У вас есть запись с номером детали 1234567-00-A. Вы ищете этот номер детали в документе поиска и находите две записи, соответствующие данному номеру детали: одна с частью группы деталей A, а другая с частью группы B. Откуда вы знаете какой из этих двух выбрать? 12.04.2015
  • Чтобы сделать это вручную, мне нужно найти в XML определенную группу деталей (например, группу деталей A) и найти все номера деталей. Затем мне нужно будет заглянуть в файл loopup и найти там те же номера деталей. Затем я бы взял только значения props="part-restrict" для номеров деталей с родственным узлом props="part-section", который соответствует группе деталей A. 12.04.2015

Ответы:


1

Вот немедленное решение для вашего преобразования. Для удобства я встроил документ поиска, и это делает трансформацию длинной, но на самом деле она короткая и понятная:

<xsl:stylesheet version="2.0"  xmlns:xsl="https://w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/> 

 <xsl:key name="part-number" match="strow" 
 use="concat(stentry[@props='part-section'], '|', stentry[@props='part-number'])" />

 <xsl:variable name="vLookup">
  <lookup>
        <strow>
            <stentry props="part-section">Part Group A</stentry>
            <stentry props="part-name">SomePart</stentry>
            <stentry props="part-number">1234567-00-A</stentry>
            <stentry props="part-restrict">Yes</stentry>
        </strow>
        <strow>
            <stentry props="part-section">Part Group A</stentry>
            <stentry props="part-name">AnotherPart</stentry>
            <stentry props="part-number">2345678-00-A</stentry>
            <stentry props="part-restrict">No</stentry>
        </strow>
        <strow>
            <stentry props="part-section">Part Group B</stentry>
            <stentry props="part-name">SomePart</stentry>
            <stentry props="part-number">1234567-00-A</stentry>
            <stentry props="part-restrict">No</stentry>
        </strow>
    </lookup>
 </xsl:variable>  

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

 <xsl:template match="stentry[@props='part-restrict']">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:variable name="matching-part" 
             select="key('part-number', 
                         concat(ancestor::refbody[1]/preceding-sibling::title[1], 
                         '|',
                         ../stentry[@props='part-number']), 
                     $vLookup)" />
         <xsl:sequence select=
           "($matching-part/stentry[@props='part-restrict'], 
             .[empty($matching-part)])/text()"/>
    </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному исходному XML-документу:

<reference>
    <title>Part Group A</title>
    <refbody>
        <section>
            <image href="partGroupA.svg"/>
        </section>
        <simpletable>
            <sthead>
                <stentry>Annotation</stentry>
                <stentry>Part Name</stentry>
                <stentry>Restricted?</stentry>
                <stentry>Part Description</stentry>
                <stentry>Part Number</stentry>
                <stentry>Quantity</stentry>
                <stentry>Comment</stentry>
            </sthead>
            <strow>
                <stentry translate="no" props="annotation">1</stentry>
                <stentry translate="no" props="part-name">SomePart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">SomePart</stentry>
                <stentry translate="no" props="part-number">1234567-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Some comment</stentry>
            </strow>
            <strow>
                <stentry translate="no" props="annotation">2</stentry>
                <stentry translate="no" props="part-name">AnotherPart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">AnotherPart</stentry>
                <stentry translate="no" props="part-number">2345678-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Another comment</stentry>
            </strow>
        </simpletable>
    </refbody>
    <title>Part Group B</title>
    <refbody>
        <section>
            <image href="partGroupB.svg"/>
        </section>
        <simpletable>
            <sthead>
                <stentry>Annotation</stentry>
                <stentry>Part Name</stentry>
                <stentry>Restricted?</stentry>
                <stentry>Part Description</stentry>
                <stentry>Part Number</stentry>
                <stentry>Quantity</stentry>
                <stentry>Comment</stentry>
            </sthead>
            <strow>
                <stentry translate="no" props="annotation">1</stentry>
                <stentry translate="no" props="part-name">SomePart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">SomePart</stentry>
                <stentry translate="no" props="part-number">1234567-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Some comment</stentry>
            </strow>
            <strow>
                <stentry translate="no" props="annotation">2</stentry>
                <stentry translate="no" props="part-name">AnotherPart</stentry>
                <stentry translate="no" props="part-restrict"></stentry>
                <stentry translate="yes" props="part-desc">AnotherPart</stentry>
                <stentry translate="no" props="part-number">2345678-00-A</stentry>
                <stentry translate="no" props="quantity">1</stentry>
                <stentry translate="yes" props="comment">Another comment</stentry>
            </strow>
        </simpletable>
    </refbody>
</reference>

получен желаемый правильный результат:

<reference>
   <title>Part Group A</title>
   <refbody>
      <section>
         <image href="partGroupA.svg"/>
      </section>
      <simpletable>
         <sthead>
            <stentry>Annotation</stentry>
            <stentry>Part Name</stentry>
            <stentry>Restricted?</stentry>
            <stentry>Part Description</stentry>
            <stentry>Part Number</stentry>
            <stentry>Quantity</stentry>
            <stentry>Comment</stentry>
         </sthead>
         <strow>
            <stentry translate="no" props="annotation">1</stentry>
            <stentry translate="no" props="part-name">SomePart</stentry>
            <stentry translate="no" props="part-restrict">Yes</stentry>
            <stentry translate="yes" props="part-desc">SomePart</stentry>
            <stentry translate="no" props="part-number">1234567-00-A</stentry>
            <stentry translate="no" props="quantity">1</stentry>
            <stentry translate="yes" props="comment">Some comment</stentry>
         </strow>
         <strow>
            <stentry translate="no" props="annotation">2</stentry>
            <stentry translate="no" props="part-name">AnotherPart</stentry>
            <stentry translate="no" props="part-restrict">No</stentry>
            <stentry translate="yes" props="part-desc">AnotherPart</stentry>
            <stentry translate="no" props="part-number">2345678-00-A</stentry>
            <stentry translate="no" props="quantity">1</stentry>
            <stentry translate="yes" props="comment">Another comment</stentry>
         </strow>
      </simpletable>
   </refbody>
   <title>Part Group B</title>
   <refbody>
      <section>
         <image href="partGroupB.svg"/>
      </section>
      <simpletable>
         <sthead>
            <stentry>Annotation</stentry>
            <stentry>Part Name</stentry>
            <stentry>Restricted?</stentry>
            <stentry>Part Description</stentry>
            <stentry>Part Number</stentry>
            <stentry>Quantity</stentry>
            <stentry>Comment</stentry>
         </sthead>
         <strow>
            <stentry translate="no" props="annotation">1</stentry>
            <stentry translate="no" props="part-name">SomePart</stentry>
            <stentry translate="no" props="part-restrict">No</stentry>
            <stentry translate="yes" props="part-desc">SomePart</stentry>
            <stentry translate="no" props="part-number">1234567-00-A</stentry>
            <stentry translate="no" props="quantity">1</stentry>
            <stentry translate="yes" props="comment">Some comment</stentry>
         </strow>
         <strow>
            <stentry translate="no" props="annotation">2</stentry>
            <stentry translate="no" props="part-name">AnotherPart</stentry>
            <stentry translate="no" props="part-restrict"/>
            <stentry translate="yes" props="part-desc">AnotherPart</stentry>
            <stentry translate="no" props="part-number">2345678-00-A</stentry>
            <stentry translate="no" props="quantity">1</stentry>
            <stentry translate="yes" props="comment">Another comment</stentry>
         </strow>
      </simpletable>
   </refbody>
</reference>

Пояснение:

Требуемые strow элементы из документа поиска идентифицируются составным ключом, состоящим из двух частей: номера части и имени группы. Таким образом, оба эти значения должны участвовать в атрибуте use= элемента <xsl:key>, чтобы идентифицировать требуемый strow.

12.04.2015
  • +1. Это также сработало, как я и ожидал, и я подумал, что это очень интересный подход. Спасибо вам за помощь. 13.04.2015
  • Не могли бы вы объяснить, почему встроенный поисковый документ имеет больше преимуществ? Я принял другой ответ, потому что он лишь немного основан на существующей таблице стилей. Наличие встроенного поиска означало бы, что мне нужно будет обновить таблицу стилей, если мне нужно будет восстановить поиск. 13.04.2015
  • @JasonDavis, я не предлагал вам встраивать документ поиска. Я встроил его только для удобства, чтобы не обращаться к дополнительному, внешнему документу в решении. Решение одинаково, независимо от того, используете ли вы встроенный или внешний документ поиска. Единственное изменение, которое вам нужно внести в приведенный выше код, это использовать: <xsl:variable name="vLookup" select ="document(your-document-uri)"> 13.04.2015
  • Да, этот тонкий нюанс был потерян для меня, поскольку я немного любитель, но теперь кажется довольно очевидным. Еще один вопрос. Я заметил использование xsl:sequence. Какую роль это играет в этой трансформации? 14.04.2015
  • @JasonDavis, вы используете XSLT 2.0, и для xslt-2.0 лучше использовать преимущественно <xsl:sequence>, чем <xsl:value-of>. В случае, когда выводятся строки, результаты от использования обеих инструкций одинаковы, однако здесь у меня однострочное то, что в оригинале было 8-строчным <xsl:choose>. Я вывожу последовательность text() дочерних элементов двух элементов, из которых может существовать только один: $matching-part/stentry или текущий узел ., когда $matching-part является пустой последовательностью. Это короткий и лучший эквивалент выражения <xsl:choose>, а также выражения XPath 2.0 if-then-else. 14.04.2015
  • @JasonDavis См. также: stackoverflow.com/questions/29524975/ 14.04.2015
  • Джейсон Дэвис, см. это: deviq.com/don-t-repeat-yourself целый раздел под названием Suspect Conditionals. И он рекомендует: Везде, где это возможно, рефакторинг этих условных выражений с использованием хорошо известных шаблонов проектирования. См. также эту презентацию (слайд 43 посвящен СУХОЙ): %20DRY/SOLID%20and%20Other%20Principles.pdf" rel="nofollow noreferrer">downloads.academy.telerik.com/svn/high-quality-code/2014/ 15.04.2015

  • 2

    Чтобы сделать это вручную, мне нужно будет найти в XML определенную группу деталей (например, группу деталей A).

    Если под этим вы подразумеваете группу частей, которая появляется в элементе title (в той части XML-документа, которую вы нам пока не показывали), то вам нужно внести два изменения в вашу таблицу стилей XSLT:

    1. Измените определение ключа на:

    <xsl:key name="part-number" match="strow" use="concat(stentry[@props='part-section'], '|', stentry[@props='part-number'])" />
    

    2. Измените определение переменной $matching-part на:

    <xsl:variable name="matching-part" select="key('part-number', concat(ancestor::reference/title, '|', ../stentry[@props='part-number']), document('pm_restrict_redo-2.xml'))" />
    
    13.04.2015
  • Вы были правы, упрекая меня за то, что я изначально не включил полный пример. Это работает отлично. Спасибо за помощь 13.04.2015
  • Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: wedx@cp9.ru