Xsl从包含Xml文档的变量中获取完整元素标记

时间:2014-03-16 21:14:52

标签: xml xslt

我有2个输入xml文件。

1)Ant Buld文件:

<project name="project">
  <target name="target1"/>
  <target name="target2"/>
</project>

2)视觉范式项目:

<Project Name="VpProj" attr1="attr" attr2="attr">
  <Models>
    <Model Id="O60QwyKGAqACZC5_" Name="ILockXml">
      <ModelChildren>
        <!-- THE FOLLOWING PACKAGE DOES NOT NEED TO BE INCLUDED IN OUTPUT, 
             IS GIVEN AS EXAMPLE -->
        <Package Id="tYTQwyKGAqACZC6R" Name="Xml Files">
        </Package>
        <!-- I WANT TO INSERT NEW PACKAGE ELEMENTS HERE, SUPPOSE A FORM OF: -->
        <!--
        <Package Id="NEWGUID!" Name="target1">
        </Package>
        <Package Id="NEWGUID!" Name="target2">
        </Package>
        -->
      </ModelChildren>
    </Model>
  </Models>
</Project>

我的输出需要具有上面的形式,但没有“Xml Files”包。

我正在使用Saxon HE,我是XSL的新手。到目前为止,我有以下内容......

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output indent="yes"/>
  <!-- THIS IS THE VpProj FILE -->
  <xsl:variable name="prj" select="document('vp-xml/project.xml')"/>
  <xsl:template match="/">
    <xsl:for-each select="$prj/Project">
      <!-- ______ I AM HERE _____ -->
      <!-- HOW DO I INJECT THE ENTIRE PROJECT ELEMENT TAG HERE? -->
    </xsl:for-each>
  </xsl:template>
</xsl:transform>

我正在命令行上传递Ant Build文件。我知道如何将更多的文字代码包装在我正在创建的包中,我希望在这个阶段的答案看起来像:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output indent="yes"/>
  <!-- THIS IS THE VpProj FILE -->
  <xsl:variable name="prj" select="document('vp-xml/project.xml')"/>

  <xsl:template match="/">
    <xsl:for-each select="$prj/Project">
      <!-- ______ I AM HERE _____ -->
      <!-- HOW DO I INJECT THE ENTIRE PROJECT ELEMENT TAG HERE? -->
      <XSL:INJECT-VP-ELEMENT-MAGIC>
        <Model Id="O60QwyKGAqACZC5_" Name="ILockXml">
          <ModelChildren>
            <xsl:template match="/project"/>
          </ModelChildren>
        </Model>
      </XSL:INJECT-VP-ELEMENT-MAGIC>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="/project">
    <xsl:for-each select="target">
      <Package>
        <xsl:attribute name="Name">
          <xsl:value-of select="./@name"/>
        </xsl:attribute>
        <xsl:attribute name="Id">
          <!-- NEED HELP WITH GUID TOO, IS TRUE GUID POSSIBLE WITH SAXON HE? -->
        </xsl:attribute>
      </Package>
    </xsl:for-each>
  </xsl:template>
</xsl:transform>

这个东西很难找到,但我到了那里。

当我说注入整个项目元素标记时,我想一般地这样做,而不是创建对元素名称及其属性的文字引用,即:

<Project>
  <xsl:attribute name="Name">
    <xsl:value-of select="$prj/Project/@name"/>
  </xsl:attribute>
  <!-- etc... DO NOT WANT THIS FORM -->
</Project>

1 个答案:

答案 0 :(得分:1)

忘掉for-each。如果您想要一个对现有XML进行调整的XSLT,并且大部分都保持不变,那么通常的方法是将其基于身份转换。然后编写与要修改的内容匹配的特定模板。以下是我将如何解决这一特定问题:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output indent="yes"/>

  <!-- This is the build.xml - you need to save this in a variable because the
       meaning of "/" changes when you're processing nodes from a different
       document -->
  <xsl:variable name="build" select="/" />

  <!-- identity transformation - copy everything as-is unless overridden -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>

  <!-- starting point -->
  <xsl:template match="/">
    <!-- process the project.xml document.  Note that we have to process
         document(...)/node() rather than just document(...) as the latter
         would match this current template, leading to an infinite loop -->
    <xsl:apply-templates select="document('vp-xml/project.xml')/node()" />
  </xsl:template>

  <!-- behave like the identity template, but also process the build file -->
  <xsl:template match="ModelChildren">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
      <xsl:apply-templates select="$build//target" />
    </xsl:copy>
  </xsl:template>

  <!-- logic to handle target elements from the build file -->
  <xsl:template match="target">
    <Package Name="{@name}" />
    <!-- and whatever else you need to do here -->
  </xsl:template>
</xsl:stylesheet>

要生成唯一标识符,XSLT具有generate-id功能,但未指定这些标识符的格式 - 不同的处理器可以以不同的格式生成它们,只要您始终为同一节点获取相同的ID并且在给定的转换运行期间,不同节点的不同ID。如果您特别需要随机ID来跟随问题中的格式,那么您可能必须使用随机数生成器自己处理它,但默认情况下在Saxon HE中没有 - 如果您有 PE 然后你可以使用EXSLT random-sequence函数:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
                xmlns:rnd="http://exslt.org/random" exclude-result-prefixes="rnd">

  <xsl:variable name="idChars" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_'" />
  <!-- rest of stylesheet as before -->

  <!-- logic to handle target elements from the build file -->
  <xsl:template match="target">
    <Package Name="{@name}" Id="{string-join(
       for $num in rnd:random-sequence(16, position())
         return substring($idChars, $num * string-length($idChars) + 1, 1),
       '')}"/>
    <!-- and whatever else you need to do here -->
  </xsl:template>
</xsl:stylesheet>