xslt создает дочерние элементы на основе имени split и родительского узла - PullRequest
2 голосов
/ 03 февраля 2011

возможно ли сделать следующее в xsl.Я пытаюсь разделить содержимое элемента и создать подэлементы на основе разделения.Чтобы сделать вещи сложнее, есть случайное исключение (то есть узел 4 не разделяется).Мне интересно, есть ли способ, которым я могу сделать это без явного разделения для каждого элемента.Опять же, не уверен, если это возможно.спасибо за помощь!

оригинальный XML:

<document>
  <node>
    <node-1>hello world1</node-1>
    <node-2>hello^world2</node-2>
    <node-3>hello^world3</node-3>
    <node-4>hello^world4</node-4>
  </node>
</document>

преобразованный XML

<document>
  <node>
    <node-1>hello world1</node-1>
    <node-2>
      <node2-1>hello</node2-1>
      <node2-2>world2</node2-2>
    </node-2>
    <node-3>
      <node3-1>hello</node3-1>
      <node3-2>world3</node3-2>
    </node-3>
    <node-4>hello^world4</node-4>
  </node>
</document>

Ответы [ 4 ]

2 голосов
/ 03 февраля 2011

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

Шаблон, соответствующий текстовым узлам для токенизации, эта более семантическая таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="text()[contains(.,'^')]" name="tokenize">
        <xsl:param name="pString" select="concat(.,'^')"/>
        <xsl:param name="pCount" select="1"/>
        <xsl:if test="$pString">
            <xsl:element name="{translate(name(..),'-','')}-{$pCount}">
                <xsl:value-of select="substring-before($pString,'^')"/>
            </xsl:element>
            <xsl:call-template name="tokenize">
                <xsl:with-param name="pString" 
                                select="substring-after($pString,'^')"/>
                <xsl:with-param name="pCount" select="$pCount + 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    <xsl:template match="node-4/text()">
        <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<document>
    <node>
        <node-1>hello world1</node-1>
        <node-2>
            <node2-1>hello</node2-1>
            <node2-2>world2</node2-2>
        </node-2>
        <node-3>
            <node3-1>hello</node3-1>
            <node3-2>world3</node3-2>
        </node-3>
        <node-4>hello^world4</node-4>
    </node>
</document>

Примечание : классический токенизатор (на самом деле используется нормализованная строка, допускающая пустые элементы в последовательности).Правила сопоставления и перезаписи шаблонов (с сохранением node-4 текстового узла).

1 голос
/ 03 февраля 2011

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

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <document>
      <node>
        <xsl:apply-templates select="document/node/*"/>
      </node>
    </document>
  </xsl:template>

  <xsl:template match="*">
    <xsl:variable name="tag" select="name()"/>

    <xsl:choose>

      <xsl:when test="contains(text(),'^')">
        <xsl:element name="{$tag}">
          <xsl:element name="{concat($tag,'-1')}">
            <xsl:value-of select="substring-before(text(),'^')"/>
          </xsl:element>
          <xsl:element name="{concat($tag,'-2')}">
            <xsl:value-of select="substring-after(text(),'^')"/>
          </xsl:element>
        </xsl:element>
      </xsl:when>

      <xsl:otherwise>
        <xsl:copy-of select="."/>
      </xsl:otherwise>

    </xsl:choose>

  </xsl:template>

</xsl:stylesheet>

Это работает, пока все узлы, которые вы хотите разделить, находятся на одном уровне, ниже /document/node.Если реальная структура документа отличается, вам придется настроить решение для соответствия.

0 голосов
/ 03 февраля 2011

решение, которое я использовал:

<xsl:output omit-xml-declaration="yes" method="xml" indent="yes"/>
<xsl:preserve-space elements="*"/>

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

<xsl:template match="node()" mode="copy">
    <xsl:call-template name="identity"/>
</xsl:template>

<xsl:template match="node-2 | node-3" name="subFieldCarrotSplitter">
    <xsl:variable name="tag" select="name()"/>
    <xsl:element name="{$tag}">
        <xsl:for-each select="str:split(text(),'^')">
            <xsl:element name="{concat($tag,'-',position())}">
                <xsl:value-of select="text()"/>
            </xsl:element>
        </xsl:for-each>
    </xsl:element>
    <xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>

0 голосов
/ 03 февраля 2011

Можете ли вы использовать XSLT 2.0?Если так, это звучит так, как будто <xsl:analyze-string> прямо на вашей аллее.Вы можете разделить на основе регулярного выражения.

Если вам нужна дополнительная информация, спросите ...

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