【问题标题】:Nest all un-nested XML elements into a new element using XSLT使用 XSLT 将所有未嵌套的 XML 元素嵌套到一个新元素中
【发布时间】:2018-10-08 23:21:11
【问题描述】:

我有一个 XML 文件,需要对其结构进行一些更正。由于所述文档的大小,这必须自动完成。
基本结构如下:

<body>
    <div author='author1'>
        <lb n='1'/>Text1
        <lb n='2'/>Text2
    </div>
    <lb n='3'/>Text3
    <lb n='4'/>Text4
    <div author='author1'>
        <lb n='5'/>Text5
    </div>
    <add>xyz</add>
    <lb n='6'/>Text6
    <lb n='7'/>Text7
    <lb n='8'/>Text8
</body>

我想做的是将div标签中没有的所有内容放入div标签中,并用属性@author='author2'进行标记。移动块的文本和结构应该保持原样,只是嵌套在div 中。订单也必须保留。
生成的 XML 应如下所示:

<body>
    <div author='author1'>
        <lb n='1'/>Text1
        <lb n='2'/>Text2
    </div>
    <div author='author2'>
        <lb n='3'/>Text3
        <lb n='4'/>Text4
    </div>
    <div author='author1'>
        <lb n='5'/>Text5
    </div>
    <div author='author2'>
        <add>xyz</add>
        <lb n='6'/>Text6
        <lb n='7'/>Text7
        <lb n='8'/>Text8
    </div>
</body>

我当前的 XSLT(我在注意到 XML 包含的元素不仅仅是 lb 之前写的)确实将 lb 放在正确的 div 中,但是它将所有内容移到底部并删除了文本。
XSLT 如下所示:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" version="2.0">

<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="*[not(self::lb)]"/>
            <div>
                <xsl:attribute name="resp">author2</xsl:attribute>
                <xsl:apply-templates select="lb"/>
            </div>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

它会返回这个 XML:

<?xml version="1.0"?>
<body><div author="author1">
        <lb n="1"/>Text1
        <lb n="2"/>Text2
    </div><div author="author1">
        <lb n="5"/>Text5
    </div><add>xyz</add><div resp="author2"><lb n="3"/><lb n="4"/><lb n="6"/><lb n="7"/><lb n="8"/></div></body>

我做错了什么?
提前感谢您的帮助!

【问题讨论】:

    标签: xml xslt xslt-1.0 xslt-2.0


    【解决方案1】:

    作为使用group-adjacent 的替代方法,您可以在xsl:for-each-group 上使用group-starting-with

    试试这个 XSLT

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
      <xsl:output method="xml" indent="yes"/>
      <xsl:strip-space elements="*" />
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="body">
        <xsl:copy>
          <xsl:for-each-group select="node()" group-starting-with="div">
            <xsl:apply-templates select="." />
            <xsl:if test="current-group()[2]">
              <div resp="author2">
                <xsl:apply-templates select="current-group()[position() gt 1]"/>
              </div>
            </xsl:if>
          </xsl:for-each-group>
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 这个很好用,谢谢!它甚至允许在文本中嵌套更多节点。
    【解决方案2】:

    尝试在 XSLT 2.0 中进行分组

    <xsl:template match="node() | @*">
            <xsl:copy>
                <xsl:apply-templates select="node() | @*"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="body">
            <xsl:copy>
            <xsl:for-each-group select="*" group-adjacent="self::lb or self::add">
                <xsl:choose>
                    <xsl:when test="current-grouping-key()">
                        <div author='author2'>
                            <xsl:apply-templates select="current-group()"/>
                        </div>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates  select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
            </xsl:copy>
        </xsl:template>
    

    https://xsltfiddle.liberty-development.net/bFDb2CW查看转换

    【讨论】:

    • 我认为您的方法很好,但您的建议忽略了文本节点,您需要&lt;xsl:for-each-group select="node()" group-adjacent="self::lb or self::add or self::text()[normalize-space()]"&gt; 而不是&lt;xsl:for-each-group select="*" group-adjacent="self::lb or self::add"&gt;,请参阅xsltfiddle.liberty-development.net/bFDb2CW/1,否则Text3 之类的内容会丢失。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    相关资源
    最近更新 更多