Как «обобщить» XSL-преобразование XML-XML для работы с файлами, имеющими разные теги, но одинаковую базовую структуру - PullRequest
2 голосов
/ 28 сентября 2011

У меня есть набор XML-файлов, подобных этому:

Пример входного файла:

<a-list>
   <a-item key_field="unique1" other="foo"/>
   <a-item key_field="unique2" other="foo"/>
   ...
</a-list>

и у меня есть преобразование, которое объединит эти файлы в один файл той же структуры. Он генерирует тот же элемент внешнего уровня (<a-list>), содержащий все элементы <a-item> из файлов, и отбрасывает дублирующиеся объекты (объекты, имеющие одно и то же поле ключа). Теперь я столкнулся с несколькими другими наборами файлов, каждый из которых очень похож по своей структуре верхнего уровня, и мне нужно выполнить почти такой же тип слияния.

Например, эти файлы могут выглядеть так:

<b-list>
   <b-item different_key_field="unique93" other="foo"/>
   <b-item different_key_field="unique94" other="foo"/>
   ...
</b-list>

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

К сожалению, мое преобразование "слияния" работает специально с именованными элементами во входных файлах (например, оно имеет шаблоны для <a-item> узлов и специально ищет дублированные атрибуты key_field). Копировать преобразование, искать / заменять имена элементов и имя ключевого атрибута довольно тривиально, но кажется крайне неэффективным дублировать один и тот же код один раз для каждого типа входного файла. Единственные отличия - это имя корневого элемента, имя элемента item и имя ключевого атрибута. То, что я хочу сделать (объединить), остается прежним.

Как я могу написать преобразование, которое может выполнять этот тип операции слияния без указания точных имен элементов / атрибута, чтобы я мог вызывать одно и то же преобразование для каждого типа файла? Есть ли способ принять имя корневого элемента, имя элемента элемента и имя ключевого атрибута в качестве параметров?

В качестве дополнительных ограничений я ограничен использованием Xalan, поэтому я считаю, что это означает только XSL 1.0, и было бы лучше избегать любых расширений.

Я думал о преобразовании XSL с другим XSL, но это кажется довольно запутанным для такой простой вещи.

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

Большое спасибо, Russ

Ответы [ 2 ]

1 голос
/ 28 сентября 2011

Вот полное решение :

<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:param name="pDoc1File" select="'b-list-file1.xml'"/>
 <xsl:param name="pDoc2File" select="'b-list-file2.xml'"/>

 <xsl:param name="pElemName" select="'b-item'"/>
 <xsl:param name="pKeyAttrName" select="'different_key_field'"/>

 <xsl:variable name="vDoc1" select="document($pDoc1File)"/>
 <xsl:variable name="vDoc2" select="document($pDoc2File)"/>


 <xsl:template match="/">
  <xsl:apply-templates select="$vDoc1/node()"/>
 </xsl:template>

 <xsl:template match="/*">
  <xsl:copy>
   <xsl:copy-of select="@*"/>
   <xsl:copy-of select=
   "*[name()=$pElemName]
      [not(@*[name()=$pKeyAttrName]
      =
      $vDoc2/*/*[name()=$pElemName]
               /@*[name()=$pKeyAttrName])
      ]"/>

   <xsl:copy-of select=
   "$vDoc2/*/*[name()=$pElemName]
      [not(@*[name()=$pKeyAttrName]
      =
      $vDoc1/*/*[name()=$pElemName]
               /@*[name()=$pKeyAttrName])
      ]"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

Файл : b-list-file1.xml

<b-list>
    <b-item different_key_field="unique93" other="foo"/>
    <b-item different_key_field="unique94" other="foo"/>    ... 
</b-list>

Файл : b-list-file2.xml

<b-list>
    <b-item different_key_field="unique92" other="foo"/>
    <b-item different_key_field="unique93" other="foo"/>    ...
</b-list>

Когда это преобразование применяется к любому XML-документу (не используется / игнорируется), получается требуемый, правильный результат :

<b-list>
   <b-item different_key_field="unique94" other="foo"/>
   <b-item different_key_field="unique92" other="foo"/>
</b-list>

Объяснение :

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

  2. Имя элементов указывается в глобальном параметре.

  3. Указывается имя атрибута "ключ"в качестве глобального / внешнего параметра.

  4. Наконец, выражения XPath в атрибутах select двух инструкций <xsl:copy-of> используют значения параметров для выбора подходящих имен.элементы и атрибуты.

Примечание : каждый XSLT-процессор имеет свою собственную реализацию установки и передачиПараметры для преобразования.Прочтите это в документации Xalan.

0 голосов
/ 28 сентября 2011

Ну, вы можете решить вашу проблему с параметрами.Не существует понятия шаблонного xsl, например, шаблонов C ++, но с помощью параметров вы можете добиться этого эффекта.Например, один из моих файлов xslt выглядит так:

<xsl:stylesheet xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xml:space="preserve" version="2.0"> 
<!--Output type to be used with the xsl:result-document-->
<xsl:output name="html" encoding="utf-8" method="html" indent="yes" doctype-   system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/> 
<!--Global output type-->
<xsl:output encoding="utf-8" method="html" indent="yes" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/> 
<!--xml output-->
<xsl:output name="xml" encoding="utf-8" method="xml" indent="yes"/>
<xsl:param name="sapFile" as="xs:string" required="yes"/>
<xsl:param name="automaticDate" as="xs:string" required="yes"/>
<xsl:param name="generatePDF" as="xs:string" required="yes"/>
<xsl:param name="fileName" as="xs:string" required="yes"/>
.
.
.

Важным элементом здесь является xsl: param.Вы можете передать эти параметры при вызове вашего xsl-преобразования.Этими параметрами в вашем случае могут быть, например: a-list, а в другом - b-list и т. Д. Затем вы можете использовать эти параметры, например $param, в любом месте кода xslt, чтобы обеспечить универсальность.

Я надеюсь, что это даст вам некоторые советы:)

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