【问题标题】:XSLT copy & setting attribute valuesXSLT 复制和设置属性值
【发布时间】:2014-04-17 21:21:23
【问题描述】:

下面是我的起始 XML:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:something-well-formed"> 
  <child1 attr1="a" attr2="b"> 
     <child1 attr1="c" attr2="b"/>
  </child1>
  <child3/>
  <child1 attr1="d" attr2="b"> 
     <child2 attr1="e" attr2="b"/> 
  </child1>
</root>

在上面运行转换后,我得到了一个中间结果 xml,其中所有属性都被剥离了,在这种情况下,是从 child1 节点:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:something-well-formed"> 
   <child1> 
      <child1/>
   </child1>
   <child3/>
   <child1> 
      <child2 attr1="e" attr2="b"/> 
   </child1>
</root>

我想做的是对上面生成的中间结果进行转换,以创建一个类似于以下示例的 xml 文档,在这种情况下,我可以指定第 n 个实例, child1 并相应地设置它的属性:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:something-well-formed"> 
   <child1  attr1="something", attr2="something else"> 
      <child1/>
   </child1>
   <child3/>
   <child1> 
      <child2 attr1="e" attr2="b"/> 
   </child1>
</root>

这是我尝试使用的示例 xslt:

<xsl:param name="element" />
    <xsl:param name="attributes" />
    <xsl:param name="nodeNumber"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[name(.)=$element]">
        <xsl:copy>
            <xsl:apply-templates select="@*" />

            <!-- Splits into separate key/value pairs elements -->
            <xsl:variable name="attributesSeq" select="tokenize($attributes, ';')" />
            <xsl:for-each select="$attributesSeq">
                <xsl:variable name="attributesSeq" select="tokenize(., ',')" />

                <xsl:variable name="key"
                    select="replace($attributesSeq[1], '&quot;', '')" />
                <xsl:variable name="value"
                    select="replace($attributesSeq[2], '&quot;', '')" />

                <xsl:attribute name="{$key}">
                    <xsl:value-of select="$value" />
                </xsl:attribute>
            </xsl:for-each>

            <xsl:apply-templates select="node()" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

问题是上面的 xslt 将“attributes”参数中的内容复制到 child1 的每个实例,而我的目标是将“attributes”参数的内容复制到 child1 的第 n 个实例。

其他问题:我希望将节点名称参数化为我选择传入的任何节点名称的第 n 个实例。上面的示例使用 child1,但它应该适用于任何节点名称(即 child3, child37 等)。

感谢您的帮助!

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    嗯。如果您将“孩子”限制为根节点的第 N 个孩子,其名称由 element 给出,您可以完全使用您的方法,但您必须替换

    <xsl:template match="*[name() = $element]">
    

    通过

    <xsl:template match="*[name() = $element][$nodeNumber]">
    

    这对我有用(尽管xsltproc 不接受语法,但我不得不改用撒克逊语)。但是,如果您想定位名称由element 给出的孩子的第N 个后代 实例,它将不起作用。这将更加棘手。我还没有找到答案。

    【讨论】:

    • xsltproc 拒绝它的原因是因为它不是有效的 XSLT 1.0 - 规范的 1.0 版禁止在 match 表达式中引用变量,2.0 版允许它们。
    • 感谢您的提示! 1.0 和 2.0 之间的这些有时细微的差异中的又一个。 :-)
    • 我猜是 XSLT 2.0 中的 tokenize()replace() 函数在 XSLT 1.0 中不存在。
    • 是的。这也是真的!不过,xsltproc 并没有抱怨这些。
    【解决方案2】:

    假设您收到此&lt;xsl:param&gt; 中的号码:

    <xsl:param name="nodeNumber" select='2'/>
    

    您可以在模板中添加谓词,将变量作为参数传递:

    <xsl:template match="*[name(.)=$element][$nodeNumber]">
       ....
    </xsl:template>
    

    这将根据元素在被调用的上下文中的位置来限制元素。

    您还有一个元素名称的参数。如果你使用:

    <xsl:param name="element" select="'child1'" />
    

    它将在child1 上添加属性。如果您将其替换为'child3''child2',它将相应地替换它们。 (显然对于child3child2 在您的示例中$nodeNumber 必须为1,因为每个只有一个。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-09
      • 2022-01-26
      • 2018-11-23
      • 1970-01-01
      • 2019-11-21
      • 1970-01-01
      • 2014-11-24
      • 1970-01-01
      相关资源
      最近更新 更多