Как проверить теги в таблице поиска

#xslt

#xslt

Вопрос:

У меня есть эта таблица поиска xml:

 <lookup>
<Codes>
<code>123<code>
</Codes>
<Codes>
<code>321<code>
</Codes>
</lookup>
  

и документ:

 <document>
<header>
<remarks>test</remarks>
</header>
<Line>
<Line-Item>
<code>123</code>
</Line-Item>
<Line-Item>
<code>444</code>
</Line-Item>
<Line-Item>
<code>321</code>
</Line-Item>
</Line>
</document>
  

Существует возможность проверить коды документов с помощью кодов таблицы поиска, и если код документа = код поиска, удалить строку из документа.

ответ должен быть:

 <document>
<header>
<remarks>test</remarks>
</header>
<Line>
<Line-Item>
<code>444</code>
</Line-Item>
</Line>
</document>
  

Я застрял на xsl: версия таблицы стилей = «1.0».
С наилучшими пожеланиями 🙂

Комментарии:

1. Хороший вопрос, 1. Смотрите мой ответ для полного решения XSLT 1.0, которое корректно работает даже в таких крайних случаях, когда все Line-Item/code значения содержатся в таблице поиска.

Ответ №1:

Это преобразование:

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

 <xsl:variable name="vCodes" select=
 "document('file:///c:/temp/LookupDelete.xml')/*/*/code"/>

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

 <xsl:template match=
 "Line-Item[code
           = document('file:///c:/temp/LookupDelete.xml')
                  /*/*/code
           ]
 "/>

 <xsl:template match=
  "Line[not(Line-Item/code
              [not(. = document('file:///c:/temp/LookupDelete.xml')
                               /*/*/code
                   )
              ]
           )
       ]
  "/>
</xsl:stylesheet>
  

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

 <document>
    <header>
        <remarks>test</remarks>
    </header>
    <Line>
        <Line-Item>
            <code>123</code>
        </Line-Item>
        <Line-Item>
            <code>444</code>
        </Line-Item>
        <Line-Item>
            <code>321</code>
        </Line-Item>
    </Line>
</document>
  

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

 <document>
   <header>
      <remarks>test</remarks>
   </header>
   <Line>
      <Line-Item>
         <code>444</code>
      </Line-Item>
   </Line>
</document>
  

Если документ такой:

 <document>
    <header>
        <remarks>test</remarks>
    </header>
    <Line>
        <Line-Item>
            <code>123</code>
        </Line-Item>
        <Line-Item>
            <code>321</code>
        </Line-Item>
        <Line-Item>
            <code>321</code>
        </Line-Item>
    </Line>
</document>
  

затем снова выдается правильный результат (обратите внимание, что ни один Line элемент вообще не выводится):

 <document>
   <header>
      <remarks>test</remarks>
   </header>
</document>
  

Комментарии:

1. Спасибо за ответ, я искал что-то такое же, как вы написали.

Ответ №2:

 <!-- codes of items to exclude from external document -->
<xsl:variable name="lookup-table" select="document('lookup-table.xml')/lookup/Codes/code"/>

<!-- exclude Line-Items with codes from lookup table -->
<xsl:template match="Line-Item[ code = $lookup-table ]"/>

<!-- 
    exclude <Line> elements, 
    which contains only <Line-Item>'s which will be removed        
-->
<xsl:template match="Line[ not(Line-Item[ code != $lookup-table ]) ]"/>

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

Комментарии:

1. К сожалению, это решение не работает в XSLT 1.0. Попробуйте его с процессором XSLT 1.0.

Ответ №3:

Эта таблица стилей выдает желаемый результат:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:lookup="lookup">
    <lookup:lookup>
        <Codes>
            <code>123</code>
        </Codes>
        <Codes>
            <code>321</code>
        </Codes>
    </lookup:lookup>
    <xsl:variable name="lookup" select="document('')/*/*/Codes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Line">
        <xsl:copy>
            <xsl:apply-templates select="@* |
                 node()[not(self::Line-Item[code=$lookup/code])]"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
  

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

Комментарии:

1. @lwburk: Я не считаю этот ответ правильным, потому что, когда все Line-Item/code значения элементов находятся в таблице поиска, он все равно создает Line элемент.

2. @Dimitre — Достаточно справедливо, но я пытаюсь представить сценарий, в котором пустой Line элемент мог бы иметь значение. Мысли?

3. @lwburk: Дело в том, что из трех ответов только ваш генерирует этот пустой Line элемент. Я знаю, что даже если бы у нас было большее количество ответов и даже если бы это соотношение было 1000: 1, вы все равно сказали бы, что есть смысл в создании пустого Line . Но это не предполагаемое «значение» — я разочарован, обнаружив, что большинство ваших недавних ответов содержат поспешные решения, которые «проще всего сделать, не задумываясь», и что вы избегаете тратить больше времени и создавать более значимые и ценные решения. Я думаю, что у вас есть потенциал для гораздо большего, и я ожидаю увидеть это.

4. @Dimitre — Я не утверждаю, что есть какая-то ценность в создании пустого Line . Я утверждаю, что это не может иметь значения.

5. @lwburk: Создание чистого вывода действительно имеет значение. Могу ли я предположить, что вы думали об исключении пустого Line элемента, но сочли это слишком сложным или отнимающим слишком много времени?