Что не так с этим подходом слияния и дедупликации? - PullRequest
1 голос
/ 17 января 2012

Учитывая этот исходный документ:

<?xml version="1.0" encoding="utf-8"?>
<config>
  <group name="global">
    <globals>
      <item grp="db" prop="userid" value="foo"/>
      <item grp="db" prop="passwd" value="bar"/>
      <item grp="log" prop="level" value="debug"/>
      <item grp="log" prop="filename" value="red.log"/>
    </globals>
  </group>
  <group name="dev">
    <globals>
      <item grp="db" prop="server" value="dev_sql_1"/>
    </globals>
    <locals>
      <item grp="db" prop="catalog" value="red_db_local"/>
      <item grp="db" prop="passwd" value="dev_passwd"/>
      <item grp="log" prop="level" value="info"/>
    </locals>
  </group>
  <group name="qa">
    <globals>
      <item grp="db" prop="server" value="qa_sql_1"/>
      <item grp="db" prop="catalog" value="qa_db"/>  <!-- this is wonky, but may happen -->
    </globals>
    <locals>
      <item grp="db" prop="catalog" value="red_db_local"/> <!-- this should beat 'qa_db' from ../globals/item[@grp='db' and prop='catalog'] -->
      <item grp="db" prop="passwd" value="qa_passwd"/>
      <item grp="log" prop="level" value="critical"/>
    </locals>
  </group>
  <group name="prod">
    <globals>
      <item grp="db" prop="server" value="prod_sql_1"/>
    </globals>
    <locals>
      <item grp="db" prop="catalog" value="prod_db_local"/>
      <item grp="db" prop="passwd" value="prod_passwd"/>
      <item grp="log" prop="level" value="critical"/>
    </locals>
  </group>
</config>

и параметр, который является одной из доступных сред, я хотел бы получить объединенный и дедуплицированный набор узлов, сохраняющий наиболее конкретные значения.Итак, для 'prod':

<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
  <item grp="db" prop="server" value="prod_sql_1"/>
  <item grp="db" prop="catalog" value="prod_db_local"/>
  <item grp="db" prop="passwd" value="prod_passwd"/>
  <item grp="log" prop="level" value="critical"/>
</config>

Я очень новичок в использовании ключей в XSLT 1.0, и я придумал эту таблицу стилей, которая работает для 'prod', но не для 'dev'или 'qa':

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:param name="environment"/>

  <!-- 
    using | to create a union of top-level global items and and env-specific items
  -->
  <xsl:variable name="all-items"
                select="/config/group[@name='global']/globals/item |
                        //group[@name=$environment]//item"/>

  <xsl:key name="dupes" match="item" use="concat(@grp,'|',@prop)"/>

  <xsl:template match="/config">
    <xsl:copy>
      <xsl:copy-of
          select="$all-items[generate-id() = generate-id(key('dupes',
                    concat(@grp,'|',@prop))[last()])]"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Я стремлюсь к следующему подходу:

  1. объединить все соответствующие <item.../> узлы в набор узлов с объединением |
  2. группировать этот набор узлов по атрибутам @grp и @prop
  3. , чтобы сохранить последний узел в любой из результирующих групп (de-dupe)

Поскольку я новичок в ключах, я могу только сказать, что я думаю этот бит кода,

<xsl:copy-of select="$all-items[generate-id() = generate-id(key('dupes',
                                            concat(@grp,'|',@prop))[last()])]"/>

выбирает узел last() из набора узлов-дубликатов.элементы, но при запуске с 'dev' или 'qa' я получаю следующее:

REG zacharyyoung$ xsltproc --stringparam environment dev config3.xsl config3.xml 
<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
</config>
REG zacharyyoung$ xsltproc --stringparam environment qa config3.xsl config3.xml
<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
</config>

Я проверил промежуточную переменную all-items для каждого параметра среды, и кажется, что по крайней мере этомногое работает правильно.

Если я переместу <group name="qa"/> на дно, например:

<config>
  <group name="global">...</group>
  <group name="dev">...</group>
  <group name="prod">...</group>
  <group name="qa">...</group>
<config>

, то запуск с 'qa' будет работать:

REG zacharyyoung$ xsltproc --stringparam environment qa config3.xsl config3.xml
<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
  <item grp="db" prop="server" value="qa_sql_1"/>
  <item grp="db" prop="catalog" value="red_db_local"/>
  <item grp="db" prop="passwd" value="qa_passwd"/>
  <item grp="log" prop="level" value="critical"/>
</config>

Итак, почему позиция <group name="...">...</group> Я выбираю вопрос?В частности, почему он работает только в последней позиции, и как мне заставить его работать для любой позиции?

РЕДАКТИРОВАТЬ 1

Когда я изолирую данные от $all-items (для любой среды) и поместить его в свой собственный файл, XSL работает правильно.Следующий пример - объединение глобалов и 'dev':

<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="db" prop="passwd" value="bar"/>
  <item grp="log" prop="level" value="debug"/>
  <item grp="log" prop="filename" value="red.log"/>
  <item grp="db" prop="server" value="dev_sql_1"/>
  <item grp="db" prop="catalog" value="red_db_local"/>
  <item grp="db" prop="passwd" value="dev_passwd"/>
  <item grp="log" prop="level" value="info"/>
</config>

, и этот XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="dupes" match="item" use="concat(@grp,'|',@prop)"/>
  <xsl:template match="/config">
    <xsl:copy>
          <xsl:copy-of
              select="item[generate-id() = generate-id(key('dupes',
                      concat(@grp,'|',@prop))[last()])]"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

приводит к:

REG zacharyyoung$ xsltproc config4.xsl config4.xml
<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
  <item grp="db" prop="server" value="dev_sql_1"/>
  <item grp="db" prop="catalog" value="red_db_local"/>
  <item grp="db" prop="passwd" value="dev_passwd"/>
  <item grp="log" prop="level" value="info"/>
</config>

Итак,теперь он, кажется, до переменной all-items?

Спасибо.

Ответы [ 2 ]

1 голос
/ 17 января 2012

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

Эта таблица стилей XSLT 1.0:

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

  <xsl:param name="environment" select="'qa'"/>

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

  <xsl:template match="group">
    <xsl:if test="@name = $environment">
      <xsl:apply-templates select="/config/group[@name='global']/globals/item[not(@prop = /config/group[@name='prod']/locals/item/@prop)]"/>
      <xsl:apply-templates/>      
    </xsl:if>
  </xsl:template>

  <xsl:template match="globals|locals">
    <xsl:apply-templates/>
  </xsl:template>

</xsl:stylesheet>

, примененный к вашему входному XML, дает желаемый результат:

<config>
   <item grp="db" prop="userid" value="foo"/>
   <item grp="log" prop="filename" value="red.log"/>
   <item grp="db" prop="server" value="qa_sql_1"/>
   <item grp="db" prop="catalog" value="red_db_local"/>
   <item grp="db" prop="passwd" value="qa_passwd"/>
   <item grp="log" prop="level" value="critical"/>
</config>

Это также работает для "prod" и "dev".

Редактировать: Удалена переменная из предиката.

0 голосов
/ 17 января 2012

Отключение Ответ DevNull (который отвечает на поставленный вопрос) Я внес следующие изменения (для некоторых неустановленных требований):

  1. Добавлены глобальные переменные окружения для смешивания, в случаетам вводится повторяющееся значение
  2. Удалено преобразование идентификаторов, поскольку оно не соответствует моим потребностям

Вот полная таблица стилей:

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

  <xsl:param name="environment" select="'qa'"/>

  <xsl:template match="/config">
    <xsl:copy>
      <xsl:copy-of select="/config/group[@name='global']/globals/item[not(@prop = /config/group[@name=$environment]//item/@prop)]"/>
      <xsl:copy-of select="/config/group[@name=$environment]/globals/item[not(@prop = /config/group[@name=$environment]/locals/item/@prop)]"/>
      <xsl:copy-of select="/config/group[@name=$environment]/locals/item"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Я все ещев надежде выяснить, что не так с ключами в моем первоначальном вопросе.

...