Как переместить элементы через XSLT - PullRequest
0 голосов
/ 12 декабря 2011

У меня есть следующий XML.

 <body>
  <p type="Heading 1">My Heading</p>
  <p>This is paragraph Text... This is paragraph text... <p type="Key Words">This is a keyword A</p></p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text... <p type="Key Words">This is a keyword B</p></p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p type="Heading 1">My Next Heading</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... <p type="Key Words">This is a keyword C</p>This is paragraph text...</p>
  <p type="Heading 2">My Next Heading</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... <p type="Key Words">This is a keyword D</p> This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
</body>

Я бы хотел переместить все «ключевые слова» непосредственно перед следующим заголовком, как показано ниже:

<body>
  <p type="Heading 1">My Heading</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p type="Key Words">This is a keyword A</p>
  <p type="Key Words">This is a keyword B</p>
  <p  type="Heading 1">My Next Heading</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p type="Key Words">This is a keyword C</p>
  <p  type="Heading 2">My Next Heading</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p>This is paragraph Text...  This is paragraph text...</p>
  <p>This is paragraph Text... This is paragraph text...</p>
  <p type="Key Words">This is a keyword D</p>
</body>

Iу меня есть код, который работает, но у него есть серьезные проблемы с производительностью, потому что я выполняю это преобразование для документов, содержащих 10 тысяч слов.Ниже мой текущий код.

<!-- Place all keywords in section right before the next heading title. -->
<xsl:template match="p[contains(@type,'Heading')]">

  <xsl:variable name="headingCount" >
    <xsl:value-of select="count(preceding::p[contains(@type,'Heading')])"/>
  </xsl:variable>

  <xsl:variable name="precedingKeyWordCount">
    <xsl:value-of select="count(preceding::p[contains(@type,'Key Words') and count(preceding::p[contains(@type,'Heading')]) = $headingCount])"/>
  </xsl:variable>


  <xsl:if test="$precedingKeyWordCount > 0" >
    <p type="Key Words">
      <xsl:apply-templates select="preceding::p[contains(@type,'Key Words') and count(preceding::p[contains(@type,'Heading')]) = $headingCount]" />
    </p>
  </xsl:if>


  <!-- place original heading -->
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>


</xsl:template>

Кто-нибудь знает более эффективный способ сделать это?

Спасибо.

Ответы [ 2 ]

1 голос
/ 13 декабря 2011

Немного более простой пример (предполагается, что Key Words параграфы могут быть полностью скопированы в вывод):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>
    <xsl:key name="byHeading" match="p[@type='Key Words']" 
             use="generate-id(following::p[starts-with(@type, 'Heading')][1])"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="body">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <xsl:copy-of select="key('byHeading', '')"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="p[starts-with(@type, 'Heading')]">
        <xsl:copy-of select="key('byHeading', generate-id())"/>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="p[@type='Key Words']"/>
</xsl:stylesheet>

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

Мы можем избежать этой проблемы с производительностью, предварительно сгруппировав key.

1 голос
/ 12 декабря 2011

Вот пример использования ключа:

<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="k1" 
    match="p/p[@type = 'Key Words']"
    use="generate-id(parent::p/following-sibling::p[starts-with(@type, 'Heading')][1])"/>

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

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

  <xsl:template match="body/p[starts-with(@type, 'Heading')]">
    <xsl:apply-templates select="key('k1', generate-id())"/>
    <xsl:call-template name="identity"/>
  </xsl:template>

  <xsl:template match="body/p[not(@type) or not(starts-with(@type, 'Heading'))]">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()[not(self::p[@type = 'Key Words'])]"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Это должно работать лучше.

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