【问题标题】:using xslt to rename node to node's name concatenated with its index使用 xslt 将节点重命名为与其索引连接的节点名称
【发布时间】:2012-04-06 10:24:56
【问题描述】:

我使用下面的 xslt 来转换 xmls,它通过 Receipt/Process 进行迭代 节点并向节点添加类型属性。根据节点的值,它将是 string/int/float。 这部分工作正常。

我还应该将“Node”节点重命名为“Node”,并与其索引和 添加一个属性,该属性应该是“名称”节点的值。

我可能有多个“节点”,我想将它们转换成这样的东西:

“Cuda3DLut”来自<Name>Cuda3DLut</Name>的第一个节点

<Node1 type="Cuda3DLut" >
<Input  type="ToolLink" role="Input" format="red,green,blue">Source</Input>
<Lut type="string">Identity</Lut>
<Output type="ToolLink" role="Output" format="red,green,blue">RESULT1</Output>
<bypass type="int">0</bypass>
<nodeRole type="string">viewing</nodeRole>
<nodeShortName type="string">LUT</nodeShortName>
</Node1>

第二个节点到

<Node2 type="CudaTool" >
...
</Node2>

如果“输入”节点的值是“MainMedia”,我也想更改为“Source”,但只有这样。

非常感谢。

Source XML:

<Receipt>

  <Process>
    <Node>
      <Name>Cuda3DLut</Name>
      <Input>MainMedia</Input>
      <Lut>Identity</Lut>
      <Output>RESULT1</Output>
      <bypass>0</bypass>
      <nodeRole>viewing</nodeRole>
      <nodeShortName>LUT</nodeShortName>
    </Node>
   <Node>
      <Name>CudaTool</Name>
      <Input>MainMedia</Input>
      <Lut>Identity</Lut>
      <Output>RESULT1</Output>
      <bypass>0</bypass>
      <nodeRole>viewing</nodeRole>
      <nodeShortName>LUT</nodeShortName>
    </Node>
  </Process>

  <Encode>
    <Job>
     ...
    </Job>
  </Encode>

</Receipt>

xslt: 

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

  <xsl:template match="/">
      <cut>
        <xsl:apply-templates/>        
    </cut>
 </xsl:template>


  <xsl:template match="Process">

      <xsl:for-each select="Node/*">

        <xsl:choose>

            <xsl:when test="name() = 'Input'">

              <xsl:copy>
                <xsl:attribute name="type">ToolLink</xsl:attribute>
                <xsl:attribute name="role">Input</xsl:attribute>
                <xsl:attribute name="format">red,green,blue</xsl:attribute>
                <xsl:apply-templates select="@*|node()" />
              </xsl:copy>              

            </xsl:when>

            <xsl:when test="name() = 'Output'">
              <xsl:copy>
                <xsl:attribute name="type">ToolLink</xsl:attribute>
                <xsl:attribute name="role">Output</xsl:attribute>
                <xsl:attribute name="format">red,green,blue</xsl:attribute>
                <xsl:apply-templates select="@*|node()" />
              </xsl:copy>              

            </xsl:when>

          <xsl:otherwise>

            <!-- Add type attribute to the node based on its value -->
            <xsl:choose>
            <xsl:when test="number(.) = .">
              <xsl:choose>
                <xsl:when test="contains(., '.')">
                <xsl:copy>
                  <xsl:attribute name="type">float</xsl:attribute>
                  <xsl:apply-templates select="@*|node()" />
                </xsl:copy>
              </xsl:when>
              <xsl:otherwise>
                <xsl:copy>
                  <xsl:attribute name="type">int</xsl:attribute>
                  <xsl:apply-templates select="@*|node()" />
                </xsl:copy>
              </xsl:otherwise>
             </xsl:choose>                                      
            </xsl:when>
            <xsl:otherwise>
              <xsl:copy>
                <xsl:attribute name="type">string</xsl:attribute>
                <xsl:apply-templates select="@*|node()" />
              </xsl:copy>            
            </xsl:otherwise>            
          </xsl:choose>

        </xsl:otherwise>            
        </xsl:choose>

      </xsl:for-each>

  </xsl:template>

  <xsl:template match="Encode">    
  </xsl:template>

</xsl:stylesheet>

【问题讨论】:

  • 你错过了向我们展示很多重要的东西,比如:1)想要的结果; 2)改造必须实现的要求。请编辑问题并提供这些 - 我们无法读懂您的想法。此外,您提供的代码与应如何生成 type 属性的要求相矛盾(与此相反)。
  • 您好 Dimitre,我更新了帖子。问候
  • 谢谢,加博尔。请看我的回答。

标签: xml xslt xls


【解决方案1】:

这种转变

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="Node">
     <xsl:element name="Node{position()}">
       <xsl:attribute name="type">
         <xsl:value-of select="Name"/>
       </xsl:attribute>
       <xsl:apply-templates select="*[not(self::Name)]"/>
     </xsl:element>
 </xsl:template>

 <xsl:template match="Node/*" priority="-1">
  <xsl:copy>
    <xsl:attribute name="type">string</xsl:attribute>
    <xsl:value-of select="."/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="Node/Input">
   <Input  type="ToolLink" role="Input" format="red,green,blue">Source</Input>
 </xsl:template>

 <xsl:template match="Output">
   <Output  type="ToolLink" role="Output" format="red,green,blue">
     <xsl:value-of select="."/>
   </Output>
 </xsl:template>

 <xsl:template match="bypass">
  <bypass type="int"><xsl:value-of select="."/></bypass>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时

<Receipt>
    <Process>
        <Node>
            <Name>Cuda3DLut</Name>
            <Input>MainMedia</Input>
            <Lut>Identity</Lut>
            <Output>RESULT1</Output>
            <bypass>0</bypass>
            <nodeRole>viewing</nodeRole>
            <nodeShortName>LUT</nodeShortName>
        </Node>
        <Node>
            <Name>CudaTool</Name>
            <Input>MainMedia</Input>
            <Lut>Identity</Lut>
            <Output>RESULT1</Output>
            <bypass>0</bypass>
            <nodeRole>viewing</nodeRole>
            <nodeShortName>LUT</nodeShortName>
        </Node>
    </Process>
    <Encode>
        <Job>      ...     </Job>
    </Encode>
</Receipt>

产生想要的正确结果:

<Node1 type="Cuda3DLut">
   <Input type="ToolLink" role="Input" format="red,green,blue">Source</Input>
   <Lut type="string">Identity</Lut>
   <Output type="ToolLink" role="Output" format="red,green,blue">RESULT1</Output>
   <bypass type="int">0</bypass>
   <nodeRole type="string">viewing</nodeRole>
   <nodeShortName type="string">LUT</nodeShortName>
</Node1>
<Node2 type="CudaTool">
   <Input type="ToolLink" role="Input" format="red,green,blue">Source</Input>
   <Lut type="string">Identity</Lut>
   <Output type="ToolLink" role="Output" format="red,green,blue">RESULT1</Output>
   <bypass type="int">0</bypass>
   <nodeRole type="string">viewing</nodeRole>
   <nodeShortName type="string">LUT</nodeShortName>
</Node2> 

【讨论】:

  • 谢谢迪米特。不幸的是,“节点”下的标签名称可能会改变,所以我需要根据值找出类型。也可能是我需要稍后为类型检测进行例外处理。我尝试将您的解决方案与 for-each 类型检测相结合。还没有运气。再次感谢。
  • @GaborForgacs:不客气。这种处理的类型根本不需要或依赖于xsl:for-each。尽量避免xsl:for-each,而是专注于功能。
  • @GaborForgacs:您“需要根据值确定类型”这一事实意味着您仍然不知道自己想要什么。这个答案解决了您在问题中定义的确切问题——如何生成名称如Nodexxx 的元素——并且该解决方案比当前接受的答案中提出的更短更简单。
  • 不幸的是,我是新手——至少根据我的活动——堆栈溢出,我只是想对另一个我不知道的答案表示赞赏。大多数情况下我同意你的观点,不幸的是我有一个移动目标,比如 40 种不同类型的节点,它们可能随时改变,我应该翻译成它们,主要区别 - 当无法检测到类型时,有未知数量的异常值 - 节点中缺少类型属性。在对 XSLT/XPATH 进行自我教育之后,我将转向您建议的方法。干杯
  • @GaborForgacs:解决复杂问题的方法是将其拆分为更小的问题。然后对于每个较小的问题,您可以在 SO 提出单独的问题。我建议不要尝试制定一个庞大且难以精确定义的问题。
【解决方案2】:

我认为您可以使用&lt;xsl:element/&gt;position() 函数生成您的节点。

<xsl:template match="Receipt/Process/Node">
    <xsl:variable name="nodename">
        <xsl:text>Node</xsl:text>
        <xsl:value-of select="position()"/>
    </xsl:variable>
    <xsl:element name="{$nodename}">
        ...
    </xsl:element>
</xsl:template>

【讨论】:

  • 不幸的是,我对模板的使用了解不多,我不确定我应该如何添加你的模板以获得预期的结果,所以基本上拥有 Node1 / Node2 /... 节点和所有层次结构中的孩子。非常感谢。
  • 我看到你用了&lt;xsl:for-each/&gt;,你可以在你的&lt;Node/&gt;元素上使用这个循环而不是我的模板,然后把我的&lt;xsl:variable/&gt;+&lt;xsl:element/&gt;放在里面。但是,您应该为自己记录有关模板的信息,使用它们非常棒!
猜你喜欢
  • 2023-04-04
  • 2021-05-20
  • 1970-01-01
  • 2013-11-27
  • 1970-01-01
  • 1970-01-01
  • 2014-07-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多