2011-02-03 128 views
2

是否可以在xsl中执行以下操作:我打算拆分一个元素的内容并根据拆分创建子元素。为了让事情变得更加棘手,偶尔会出现异常(即node-4不会分裂)。我想知道是否有一种方法,我可以做到这一点,没有为每个元素硬编码的明确分割。再次,不确定这是否可能。谢谢您的帮助!xslt根据拆分和父节点名生成子节点

原始的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> 

回答

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下的节点。如果真正的文档结构不同,您将不得不调整解决方案以匹配。

+0

很好地完成。谢谢。我改变了一下,这样你就可以使用foreach和positon()来分割N个子节点。再次感谢! – user364939 2011-02-03 19:53:31

+0

发布我的最终解决方案低于它使用的情况下,大多数人的吉姆的感兴趣 – user364939 2011-02-03 20:01:55

+0

的问题明确地指出:*为了让事情变得棘手有偶尔的例外(即节点4没有得到分)* – 2011-02-03 20:41:28

0

您可以使用XSLT 2.0吗?如果是这样,这听起来像<xsl:analyze-string>是你的胡同。你可以基于正则表达式分割。

如果您需要进一步的细节,问...

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> 

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文本节点)。