【问题标题】:Split XML nodes based on particular text根据特定文本拆分 XML 节点
【发布时间】:2015-01-18 15:45:02
【问题描述】:

请建议如何根据特定的注释文本()拆分 xml 节点。我尝试通过使用 xsl:text disable-output-escaping 格式来放置所需的结束和开始标签(元素)。

  • 我的代码是静态的,如何使动态代码适用于评论文本的任意数量的祖先,即如果祖先计数为 'n',则来自 n to 1如何利用call-template方法。
  • 出现了一些不是内容祖先的空节点,如何避免这些

我参考了我们网站上的一些建议,但很难理解其中的逻辑。请建议。 (XSLT 2 版本)

XSLT:

<root>
    <a>
        <b>The text1
            <c>
                <d>The text2</d><d>The text3</d><!--Break--><d>The text4</d>
                <e>The text5<!--Break--></e>
            </c>
            <f>The text6</f>
        </b>
    </a>
</root>

XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:template match="@*|node()">
     <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
   </xsl:template>

   <xsl:template match="//comment()[contains(., 'Break')]">
       <xsl:variable name="varAncestorCount" select="count(ancestor::*)"/>
       <xsl:choose>
           <xsl:when test="$varAncestorCount = 4">
               <xsl:text disable-output-escaping="yes">&lt;/</xsl:text><xsl:value-of select="ancestor::*[1]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                   <xsl:text disable-output-escaping="yes">&lt;/</xsl:text><xsl:value-of select="ancestor::*[2]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                       <xsl:text disable-output-escaping="yes">&lt;/</xsl:text><xsl:value-of select="ancestor::*[3]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                           <xsl:text disable-output-escaping="yes">&lt;/</xsl:text><xsl:value-of select="ancestor::*[4]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                               <xsl:comment><xsl:value-of select="."/></xsl:comment>
                           <xsl:text disable-output-escaping="yes">&lt;</xsl:text><xsl:value-of select="ancestor::*[4]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>    
                       <xsl:text disable-output-escaping="yes">&lt;</xsl:text><xsl:value-of select="ancestor::*[3]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                   <xsl:text disable-output-escaping="yes">&lt;</xsl:text><xsl:value-of select="ancestor::*[2]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
               <xsl:text disable-output-escaping="yes">&lt;</xsl:text><xsl:value-of select="ancestor::*[1]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
           </xsl:when>
           <xsl:when test="$varAncestorCount = 5">
               <xsl:text disable-output-escaping="yes">&lt;/</xsl:text><xsl:value-of select="ancestor::*[1]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                   <xsl:text disable-output-escaping="yes">&lt;/</xsl:text><xsl:value-of select="ancestor::*[2]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                       <xsl:text disable-output-escaping="yes">&lt;/</xsl:text><xsl:value-of select="ancestor::*[3]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                           <xsl:text disable-output-escaping="yes">&lt;/</xsl:text><xsl:value-of select="ancestor::*[4]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                               <xsl:text disable-output-escaping="yes">&lt;/</xsl:text><xsl:value-of select="ancestor::*[5]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                                   <xsl:comment><xsl:value-of select="."/></xsl:comment>
                               <xsl:text disable-output-escaping="yes">&lt;</xsl:text><xsl:value-of select="ancestor::*[5]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>    
                           <xsl:text disable-output-escaping="yes">&lt;</xsl:text><xsl:value-of select="ancestor::*[4]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>    
                       <xsl:text disable-output-escaping="yes">&lt;</xsl:text><xsl:value-of select="ancestor::*[3]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
                   <xsl:text disable-output-escaping="yes">&lt;</xsl:text><xsl:value-of select="ancestor::*[2]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
               <xsl:text disable-output-escaping="yes">&lt;</xsl:text><xsl:value-of select="ancestor::*[1]/name()"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>
           </xsl:when>
       </xsl:choose>

   </xsl:template>

 </xsl:stylesheet>

期望的输出:

<root>
    <a>
        <b>The text1
            <c>
                <d>The text2</d>
                <d>The text3</d>
            </c>
        </b>
    </a>
</root>
<!--Break-->
<root>
    <a>
        <b>
            <c>
                <d>The text4</d>
                <e>The text5</e>
            </c>
        </b>
    </a>
</root>
<!--Break-->
<root>
    <a>
        <b>
            <f>The text6</f>
        </b>
    </a>
</root>

【问题讨论】:

    标签: xslt


    【解决方案1】:

    [呻吟]你在哪里找到这些“有趣”的任务?

    永远不要要求您使用转义文本手动形成 XML 节点。

    试试下面的样式表。它可能会更精简,但我相信它解决了这里的主要问题:

    XSLT 2.0

    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:variable name="root" select="/*" />
    
    <xsl:template match="/">
        <super-root>
            <xsl:for-each select="0 to count(//comment()[.='Break'])">
                <xsl:apply-templates select="$root">
                    <xsl:with-param name="i" select="." tunnel="yes"/>
                </xsl:apply-templates>
                <xsl:if test="position()!=last()">
                    <xsl:comment>Break</xsl:comment>
                </xsl:if>
            </xsl:for-each >
        </super-root>
    </xsl:template>
    
    <xsl:template match="@*|node()">
        <xsl:param name="i" tunnel="yes"/>
            <xsl:if test="descendant-or-self::text()[count(preceding::comment()[.='Break'])=$i]">
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:if>
    </xsl:template>
    
    </xsl:stylesheet>
    

    结果:

    <?xml version="1.0" encoding="UTF-8"?>
    <super-root>
       <root>
          <a>
             <b>The text1
                <c>
                   <d>The text2</d>
                   <d>The text3</d>
                </c>
             </b>
          </a>
       </root>
       <!--Break-->
       <root>
          <a>
             <b>
                <c>
                   <d>The text4</d>
                   <e>The text5</e>
                </c>
             </b>
          </a>
       </root>
       <!--Break-->
       <root>
          <a>
             <b>
                <f>The text6</f>
             </b>
          </a>
       </root>
    </super-root>
    

    【讨论】:

    • 掌声将 OP 从禁用输出转义中重定向。
    • @Michael,非常感谢您提供的漂亮 XSLT 代码。它可以按要求完美运行。如果有任何进一步的要求,我可以要求相关的这个职位吗?请。
    • @Michael,如果需要在元素“b”内拆分,请提出建议。
    • @RudramuniTP 我相信您可以选择任何节点作为“中断节点”,而不是&lt;xsl:for-each select="0 to count(//comment()[.='Break'])"&gt; 和&lt;xsl:if test="descendant-or-self::text()[count(preceding::comment()[.='Break'])=$i]"&gt; 中的评论。
    • @Michael,抱歉我的要求不明确。现在'b'不再是多次拥有根节点,而是最顶层的break祖先('b'将多次出现)并且主根也将在那里一次。 Break 将取决于像往常一样的评论“Break”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 2014-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多