xslt根据拆分和父节点名称生成子项

时间:2011-02-03 17:41:32

标签: xslt

是否可以在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 个答案:

答案 0 :(得分:2)

  

为了让事情变得更加棘手   偶然的例外(即节点-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 :(得分:1)

这是一个XSL 1.0解决方案。我认为样本输出中node-4的不一致只是一个错字。否则,你必须定义为什么node3被拆分而node4不是。

<?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下的同一级别,这就可以正常工作。如果真实文档结构不同,您将不得不调整解决方案以匹配。

答案 2 :(得分:0)

您可以使用XSLT 2.0吗?如果是这样,听起来<xsl:analyze-string>就在你的小巷里。您可以根据正则表达式进行拆分。

如果您需要更多详细信息,请询问......

答案 3 :(得分:0)

我使用的解决方案:

<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>