Конкатировать конкретное содержимое элемента тега XML на множественное вхождение, используя xsl - PullRequest
0 голосов
/ 07 октября 2018

У меня есть входной XML, который необходимо преобразовать, чтобы объединить теги p и тег p с атрибутами, но я не могу получить представление об этом, поскольку повторение может быть динамическим. А также остальная часть содержимого XMLдолжен быть скопирован как есть,

Входной XML:

    <Node1>
      <head>first</head>
      <body>Second</body>
      <p>This is initial tag.</p>
      <p merge="Y">Additional tag.</p>
      <p merge="Y">Tag1.</p>
      <p merge="Y">Tag2.</p>
      <p merge="Y">Tag3.</p>
      <p merge="Y">TagN.</p>
      <tail>third</tail>
    </Node1>

Ожидаемый выходной XML:

     <Node1>
        <head>first</head>
        <body>Second</body>
        <p>This is initial tag.Additional tag.Tag1.Tag2.Tag3.TagN.</p>
        <tail>third</tail>
     </Node1>

тег p должен быть объединен с тегом p с merge ="y" атрибуты содержимого, и возможно, что это может быть несколько тегов p с merge = "y" с N числом повторений.Есть ли способ, это может быть объединено с кодом XSL.

Может кто-нибудь наставить меня в этом.Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Вы можете попытаться набрать элементы p merge="Y" на предыдущем родственнике p:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>

  <xsl:key name="initial-p" match="p[@merge = 'Y']" use="generate-id(preceding-sibling::p[not(@merge = 'Y')][1])"/>

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

  <xsl:template match="Node1/p[not(@merge = 'Y')]">
      <xsl:copy>
          <xsl:apply-templates select="node() | key('initial-p', generate-id())/node()"/>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="Node1/p[@merge = 'Y']"/>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / gWmuiK1

Что касается использования ключей: таблица стилей определяет ключ <xsl:key name="initial-p" match="p[@merge = 'Y']" use="generate-id(preceding-sibling::p[not(@merge = 'Y')][1])"/>, что означает, что процессор XSLT индексирует элементы p[@merge = 'Y'] в сгенерированном идентификаторе первого предшествующего брата p, не имеющего этого атрибута merge.Затем шаблон для этих элементов p (т.е. match="Node1/p[not(@merge = 'Y')]") может выбрать индексированные элементы p[@merge = 'Y'], вызвав функцию key с key('initial-p', generate-id()), а key('initial-p', generate-id())/node() просто проверяет только содержимое этих элементовобрабатывается далее (что означает, что в контексте полной таблицы стилей содержимое копируется шаблоном преобразования идентификаторов).

Подробнее об использовании ключей можно узнать в любом учебнике по XSLT, например, в книге «Практическое преобразование».Использование XSLT и XPath "доступно онлайн на https://cranesoftwrights.github.io/books/ptux/index.htm имеет подраздел" Ссылки на ключевые узлы XSLT "в главе 7, раздел 4.

0 голосов
/ 07 октября 2018

Чтобы объединить «начальный» <p> элемент (без merge attribute = 'Y') со следующими <p> элементами (с merge attribute = 'Y'), вам необходим шаблон, соответствующий "p".

Внутри этого шаблона должно быть <xsl:if test="not(@merge = 'Y')"> для обслуживания только"начальных" элементов.

Инструкция по копированию содержимого должна включать:

  • текущий элемент,
  • после <p> братьев и сестер с @merge = 'Y' (предикат № 1),
  • , но только с «прямыми братьями и сестрами», т.е. не предшествует другой «начальный»«Элемент <p> (предикат № 2),
  • с пустым separator (по умолчанию это пробел).

Таким образом, скрипт работает нормально, даже если у вас есть другой»начальный элемент "<p> с (другой) следующей последовательностью <p> элементов, подлежащих объединению (как в моем примере, приведенном ниже).

Таким образом, сценарий XSLT может быть следующим:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>

  <xsl:template match="p">
    <xsl:if test="not(@merge = 'Y')">
      <xsl:copy>
        <xsl:value-of select="., following-sibling::p[@merge = 'Y']
          [generate-id(preceding-sibling::p[not(@merge = 'Y')][1])
            = generate-id(current())]"
          separator=""/>
      </xsl:copy>
    </xsl:if>
  </xsl:template>

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

Рабочий пример см. http://xsltfiddle.liberty -development.net / gWmuiJZ

В XSLT 1.0 некоторые изменения необходимыded, потому что value-of в версии 1.0 работает немного по-другому (и не поддерживает атрибут separtor).Чтобы обойти эту проблему, вы должны использовать отдельный value-of для текущего элемента и for-each loop (с другим value-of) для следующих братьев и сестер.

Пример в версии 1.0 см. http://xsltransform.net/3MEbY7K

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