【问题标题】:Copy child nodes and change element names with XSL使用 XSL 复制子节点并更改元素名称
【发布时间】:2014-06-10 16:07:30
【问题描述】:

我有来自供应商的这个源 XML:

源 XML

<?xml version="1.0" encoding="UTF-8"?>
<src:view name="books"
    xmlns="xyz.com/wow"
    xmlns:src="xyz.com/fun" 
    xmlns:xsi="w3.org/2001/XMLSchema-instance">
    <books>
        <title>Searching for Answers</title>
    </books>
    <books>
        <title>Get Rich Quick</title>   
    </books>
    <books>
        <title>Negotiating with the Grim Reaper</title> 
    </books>    
</src:view>

我想转换成一个带有根元素books 的新文档,然后复制所有books 元素,但将名称从books 更改为books_record。文档将是任意的(books 今天,widgets 明天,等等),但根的孩子的元素名称始终可以从 /@name 获得,这是供应商约定。

预期输出

<books>
   <books_record>
      <title>Searching for Answers</title>
   </books_record>
   <books_record>
      <title>Get Rich Quick</title>
   </books_record>
   <books_record>
      <title>Negotiating with the Grim Reaper</title>
   </books_record>
</books>

我管理了正确的根元素和所有子元素的复制,但我不确定如何将所有 &lt;books&gt; 更改为 &lt;books_record&gt;。另外,到目前为止,我所拥有的是否有效且有效?我知道它有效,只是不能 100% 确定它是否是最好的方法。

到目前为止的 XSL(在 michael.hor257k 的帮助下更新)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    exclude-result-prefixes="xsl" version="2.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8"
        indent="yes" />
    <xsl:strip-space elements="*" />

<xsl:template match="*">
    <xsl:element name="{local-name()}">
        <xsl:copy-of select="@*" />
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>

<xsl:template match="/*">
    <xsl:variable name="rootElementName">
        <xsl:value-of select="@name" />
    </xsl:variable>     
    
    <xsl:element name="{$rootElementName}">      
            <xsl:apply-templates /> 
    </xsl:element>       
  
</xsl:template>

<xsl:template match="/*/node()">
    <xsl:variable name="rootElementName">
        <xsl:value-of select="/*/@name" />
    </xsl:variable>

    <xsl:element name="{$rootElementName}_record">      
            <xsl:apply-templates /> 
    </xsl:element>          
</xsl:template>
</xsl:transform>

【问题讨论】:

    标签: xml xslt xslt-2.0


    【解决方案1】:

    我相信您可以将其简化为:

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
    <xsl:strip-space elements="*" />
    
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:copy-of select="@*" />
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="/*">
        <books>
            <xsl:apply-templates />
        </books>
    </xsl:template>
    
    <xsl:template match="*[local-name()='books']">
        <books_record>
            <xsl:apply-templates />
        </books_record>
    </xsl:template>
    
    </xsl:transform>
    

    当然,如果你知道输入的预期格式,你可以得到更明确的 - 因此更短的更有效,例如:

    <xsl:transform version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:src="xyz.com/fun" 
    xmlns:wow="xyz.com/wow"
    exclude-result-prefixes="src wow">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
    
    <xsl:template match="/">
        <books>
            <xsl:for-each select="src:view/wow:books">
                <books_record>
                    <title>
                        <xsl:value-of select="wow:title"/>
                    </title>
                </books_record>
            </xsl:for-each>
        </books>
    </xsl:template> 
    
    </xsl:transform>
    

    编辑:

    如果我正确理解您所说的“通用”是什么意思,那么:

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
    <xsl:strip-space elements="*" />
    
    <xsl:variable name="tableName" select="/*/@name" />
    
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:copy-of select="@*" />
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="/*">
        <xsl:element name="{$tableName}">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="*/*">
         <xsl:element name="{$tableName}_record">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    
    </xsl:transform>
    

    注意:

    1. 变量只定义一次;
    2. 这部分不是必须的:
      exclude-result-prefixes="xsl"

    【讨论】:

    • 子元素可以并且将会发生变化,所以我试图成为通用的。
    • @raffian 好吧,然后使用第一个版本。但是,请记住,XSLT 并不是真正的通用。
    • 谢谢,在您的帮助下,我删除了显式字段名称,不是通用的,您能确认一下吗?
    • 等等,我搞砸了!忘记在我的更新中删除显式的 &lt;books&gt; 根元素,
    • 好的,已修复,现在可以使用,纯属通用,感谢您的帮助!
    猜你喜欢
    • 2019-01-18
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    相关资源
    最近更新 更多