Xml 恢复XSLT中的数据

Xml 恢复XSLT中的数据,xml,xslt,xpath,Xml,Xslt,Xpath,我有以下XML数据: <root> (...) <items> <item> (...) <custom1>blabla</custom1> <custom2>blibli</custom2> <custom3>blublu</custom3> <custom4/> <custom5/

我有以下XML数据:

<root>
  (...)
  <items>
    <item>
      (...)
      <custom1>blabla</custom1>
      <custom2>blibli</custom2>
      <custom3>blublu</custom3>
      <custom4/>
      <custom5/>
      <custom6/>
      <custom7/>
      <custom8/>
      <custom9/>
      <custom10/>
      (...)
    </item>
    <item>
      (...)
      <custom1/>
      <custom2/>
      <custom3/>
      <custom4>bloblo</custom1>
      <custom5>bleble</custom2>
      <custom6/>
      <custom7/>
      <custom8/>
      <custom9/>
      <custom10/>
      (...)
    </item>
  </items>
  (...)
</root>

(...)
(...)
布拉布拉
blibli
布鲁
(...)
(...)
布洛
bleble
(...)
(...)
我需要(使用XSLT 1.0)将其转换为:

<root>
  (...)
  <items>
    <item>
      (...)
      <refVariables>
        <refVariable uuid="var1" value="blabla"/>
        <refVariable uuid="var2" value="blibli"/>
        <refVariable uuid="var3" value="blublu"/>
      </refVariables>
      (...)
    </item>
    <item>
      (...)
      <refVariables>
        <refVariable uuid="var4" value="bloblo"/>
        <refVariable uuid="var5" value="bleble"/>
      </refVariables>
      (...)
    </item>
  </items>
  (...)
  <variables>
    <variable uuid="var1">
      <name>var1</name>
      <comment>Migrated</comment>
    </variable>
    <variable uuid="var2">
      <name>var2</name>
      <comment>Migrated</comment>
    </variable>
    <variable uuid="var3">
      <name>var3</name>
      <comment>Migrated</comment>
    </variable>
    <variable uuid="var4">
      <name>var4</name>
      <comment>Migrated</comment>
    </variable>
    <variable uuid="var5">
      <name>var5</name>
      <comment>Migrated</comment>
    </variable>
  </variables>
</root>

(...)
(...)
(...)
(...)
(...)
(...)
var1
迁移
var2
迁移
var3
迁移
var4
迁移
var5
迁移
要继续,我需要:

  • 将所有节点转换为更“通用”的形式:
  • 仅为源中的非空节点创建所有节点
  • 第一部分并不容易,但我最终找到了一个令我满意的解决方案

    但对于第二部分,我不知道该怎么做,也不知道这是否可能…

    这应该是可行的:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes"/>
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="items">
        <xsl:copy>
          <xsl:apply-templates/>
        </xsl:copy>
    
        <variables>
          <xsl:for-each select="item/*[string(.)]">
            <variable uuid="var{substring-after(name(), 'custom')}">
              <name>
                <xsl:value-of select="concat('var', substring-after(name(), 'custom'))"/>
              </name>
            </variable>
          </xsl:for-each>
        </variables>
    
      </xsl:template>
    
      <xsl:template match="item">
        <xsl:copy>
          <refVariables>
            <xsl:apply-templates select="*[string(.)]"/>
          </refVariables>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="*[starts-with(name(), 'custom')]">
        <refVariable uuid="var{substring-after(name(), 'custom')}" value="{.}" />
      </xsl:template>
    
    </xsl:stylesheet>
    

    多亏了Kirill Polishchuk,我从他那里借用了用于跳过空节点的
    字符串(.
    的“技巧”,这里是我自己的(可能是最终的)解决方案,它似乎工作得很好:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <!-- identity transform -->
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:variable name="legacy-custom-prefix" select="'custom'"/>
    
        <!-- A helper to Generate a variable reference for N non empty same customX fields -->
        <xsl:template name="variableGenerator">
            <xsl:param name="nodes"/>
            <xsl:for-each select="$nodes[string(.)][1]">
                <variable uuid="var{substring-after(name(), $legacy-custom-prefix)}">
                    <name><xsl:value-of select="concat('var', substring-after(name(), $legacy-custom-prefix))"/></name>
                    <comment>Migrated</comment>
                </variable>
            </xsl:for-each>
        </xsl:template>
    
        <!-- Generate all variables declarations -->
        <xsl:template match="/root">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
                <variables>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom1"/></xsl:call-template>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom2"/></xsl:call-template>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom3"/></xsl:call-template>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom4"/></xsl:call-template>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom5"/></xsl:call-template>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom6"/></xsl:call-template>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom7"/></xsl:call-template>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom8"/></xsl:call-template>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom9"/></xsl:call-template>
                    <xsl:call-template name="variableGenerator"><xsl:with-param name="nodes" select="//custom10"/></xsl:call-template>
                </variables>
            </xsl:copy>
        </xsl:template>
    
        <!-- Substitute legacy customX fields by variable references -->
        <xsl:template match="/root/items/item">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
                <refVariables>
                    <xsl:for-each select="node()[starts-with(name(), $legacy-custom-prefix)][string(.)]">
                        <xsl:element name="refVariable">
                            <xsl:attribute name="uuid">
                                <xsl:value-of select="concat('var', substring-after(name(.), $legacy-custom-prefix))"/>
                            </xsl:attribute>
                            <xsl:attribute name="value">
                                <xsl:value-of select="node()"/>
                            </xsl:attribute>
                        </xsl:element>
                    </xsl:for-each>
                </refVariables>
            </xsl:copy>
        </xsl:template>
    
        <!-- remove all custom fields for everyone -->
        <xsl:template match="/root/items/item/*[starts-with(name(), 'custom')]"/>
    </xsl:stylesheet>
    
    
    迁移
    
    谢谢,我们就快到了,但仍然有重复。我刚刚纠正了我的代码示例,因为它没有我真正的word版本准确。