罕见的XSLT转换

时间:2012-02-24 20:32:25

标签: ruby xml xslt

我正在尝试使用XSLT进行转换。这是我的XML源:

<Memoria>
  <seccion>
    <contenido><p>TEXT</p>
    <ul>
      <li>LIST</li>
    </ul>
    <p>ANOTHER TEXT</p>
    <p>&amp;nbsp;</p></contenido>
  </seccion>      
</Memoria>

我正在尝试使用XSLT:

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

<xsl:output method="xml" indent="yes"/>
<xsl:template match="/Memoria">
<cosa>
  <xsl:for-each select="seccion">
  <Address>
    <xsl:for-each select="contenido">
    <FirstName><xsl:value-of select="p" /></FirstName>
    </xsl:for-each>
    <ul>
      <LastName><xsl:value-of select="ul/li" /></LastName>
   </ul>
  </Address>
  </xsl:for-each>
 </cosa>
</xsl:template>

</xsl:stylesheet>

得到这个:

<?xml version="1.0"?>
<cosa>
  <Address>
    <FirstName>TEXT</FirstName>
    <ul>
      <LastName>LIST</LastName>
   </ul>
  </Address>
</cosa>

但我希望:

<?xml version="1.0"?>
<cosa>
  <Address>
    <FirstName>TEXT</FirstName>
    <ul>
      <LastName>LISTr</LastName>
   </ul>
   <FirstName>ANOTHER TEXT</FirstName>
  </Address>
</cosa>

我从外部应用程序获取此XML。

4 个答案:

答案 0 :(得分:3)

罕见的转型?提供了适当的输入XML和所需的输出,它在XSLT中并不罕见..
老实说,我对您的示例输入和输出XML不满意。我想出了一个XML希望这就是你的XML真正的样子。如果没有,那么就提出精确的i / p和o / p XML。

<?xml version="1.0" encoding="utf-8"?>
<Memoria>
  <seccion>
    <contenido>
      <p>TEXT</p>
      <ul>
        <li>Item1</li>
        <li>Item2</li>
        <li>Item3</li>
      </ul>
      <p>ANOTHER TEXT</p>
      <ul>
        <li>Itema</li>
        <li>Itemb</li>
        <li>Itemc</li>
      </ul>
    </contenido>
  </seccion>
</Memoria>

对应的XSLT代码:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <cosa>
      <xsl:apply-templates select="//contenido"/>
    </cosa>
  </xsl:template>

  <xsl:template match="text()"/>

  <xsl:template match="contenido">
    <Address>
      <xsl:apply-templates select="p|ul"/>
    </Address>
  </xsl:template>

  <xsl:template match="p[not(contains(.,'&amp;'))]">
    <FirstName>
      <xsl:value-of select="."/>
    </FirstName>
  </xsl:template>

  <xsl:template match="ul">
    <ul>
      <xsl:for-each select="li">
    <LastName>
      <xsl:value-of select="."/>
    </LastName>
      </xsl:for-each>
    </ul>
  </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

我不确定你想要实现什么......但是,以下XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/Memoria">
        <cosa>
            <xsl:for-each select="seccion">
                <Address>
                    <xsl:apply-templates select="contenido" />
                </Address>
            </xsl:for-each>
        </cosa>
    </xsl:template>

    <xsl:template match="contenido">
        <xsl:apply-templates select="p | ul" />
    </xsl:template>

    <xsl:template match="p">
        <FirstName>
            <xsl:value-of select="text()"/>
        </FirstName>
    </xsl:template>

    <xsl:template match="ul">
        <ul>
            <LastName>
                <xsl:value-of select="li"/>
            </LastName>
        </ul>
    </xsl:template>

</xsl:stylesheet>

将产生以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<cosa>
    <Address>
        <FirstName>TEXT</FirstName>
        <ul>
            <LastName>LIST</LastName>
        </ul>
        <FirstName>ANOTHER TEXT</FirstName>
        <FirstName>&amp;nbsp;</FirstName>
    </Address>
</cosa>

您现在可以考虑添加条件以从输出中排除&amp;&nbsp;元素:

<xsl:template match="p">
    <xsl:if test="not(contains(text(), '&amp;'))">
    <FirstName>
        <xsl:value-of select="text()"/>
    </FirstName>
    </xsl:if>
</xsl:template>

答案 2 :(得分:0)

xsl:value-of将获取节点集中第一个元素的内容。如果您想对集合中的所有元素进行操作,则需要xsl:for-eachxsl:apply-templates。但是,如果你这样做,你会得到:

<?xml version="1.0"?>
<cosa>
  <Address>
    <FirstName>TEXT</FirstName>
    <ul>
      <LastName>LISTr</LastName>
   </ul>
   <FirstName>ANOTHER TEXT</FirstName>
   <FirstName>&amp;&nbsp;</FirstName>
  </Address>
</cosa>

答案 3 :(得分:0)

假设您确定在第一个P元素中始终具有FirstName,并且在第二个P元素中具有第二个第一个名称,则可以使用公共node-set()函数来获取for-中的特定元素。每个循环:

以下修改后的XSLT会生成您在问题中所需的输出:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exsl="http://exslt.org/common">

  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/Memoria">
    <cosa>
      <xsl:for-each select="seccion">
        <Address>
          <xsl:for-each select="contenido">
            <FirstName>
              <xsl:value-of select="p" />
            </FirstName>
            <ul>
              <LastName>
                <xsl:value-of select="ul/li" />
              </LastName>
            </ul>
            <FirstName>
              <xsl:value-of select="exsl:node-set(.)/p[2]/."/>
            </FirstName>
          </xsl:for-each>
        </Address>  
      </xsl:for-each>
    </cosa>
  </xsl:template>

</xsl:stylesheet>

注意:我通常使用xmlns:msxsl =“urn:schemas-microsoft-com:xslt”作为node-set()函数,但我认为exsl不是特定于供应商的:)

如果您的XML结构不一致或不可预测,这可能会中断;否则它将工作,你不需要另一个for-each来获得第二个FirstName结果元素的第二个P元素。

我希望这有用!