输出整个XML作为属性

时间:2012-07-23 20:38:06

标签: xml xslt xpath xslt-1.0

我是XML和XSL Stylesheets的新手,我的任务是为我们的一个客户创建样式表。我已经创建了一个样式表,它以下列格式输出XML:

<Trip TripType="Normal">
    <Plan BeginTime="2011-08-13T10:00:00" UserDefinedTripID="777" UserDefinedRouteID="777">
        <PlanStop ArrivalTime="2011-08-13T15:30:00" ArrivalLock="true" SiteID="1" PassThru1="test1" PassThru2="test2" PassThru3="test3" PassThru4="test4">
            <PlanNote Line1="Freeform Text" Line2="Line2" Line3="Line3" />
            <PlanCargo Duration="60" BillID="" Weight="100" Units="100.0" XUnitTypeID="10" Action="Pick" />
            <PlanNote Line1="Freeform Text" Line2="Line2" Line3="Line3" />
            <PlanCargo Duration="60" BillID="" Weight="100" Units="100.0" XUnitTypeID="12" Action="Pick" />
        </PlanStop>
    </Plan>
</Trip>

我需要获取输出并将内容插入Trip元素中的属性,如下所示:

<Trip TripID="-1" CurrentRevisionNumber="1" IsDispatch="1" IsActive="0" 
IsComplete="0" OrganizationID="4"
TripData="&lt;Trip TripType=&quot;Normal&quot;&gt;
  &lt;Plan BeginTime=&quot;2011-08-13T10:00:00&quot; UserDefinedTripID=&quot;777&quot;
  UserDefinedRouteID=&quot;777&quot;&gt;
    &lt;PlanStop ArrivalTime=&quot;2011-08-13T10:00:00&quot; ArrivalLock=&    quot;true&quot; SiteID=&quot;1&quot; PassThru1=&quot;test1&quot; PassThru2=&    quot;test2&quot; PassThru3=&quot;test3&quot; PassThru4=&quot;test4&quot;&gt;
    &lt;PlanCargo Duration=&quot;45&quot; BillID=&quot;&quot; Weight=&    quot;100&quot; Units=&quot;100.0&quot; XUnitTypeID=&quot;9&quot; Action=&quot;Pick&quot;     /&gt;
    &lt;/PlanStop&gt; />

换句话说,我需要获取现有的XML输出,并在执行某些字符转换时将其放在属性中。

是的,它非常难看,但这就是他们想要的。我正在考虑制作另一个XSL,它将复制原始XSL转换的XML输出并将其放在属性中,同时将&lt;,&gt;,“等转换为&lt;,&gt;,”等等(不知道是什么他们被称为)。

我已经在互联网上寻找解决方案,但我似乎找不到任何类似的东西(我想这是因为这是一个荒谬的请求)。如有必要,我可以提供我原来的XSL,但如果可能的话,我宁愿不改变它。

提前致谢!

4 个答案:

答案 0 :(得分:3)

我必须同意其他评论者的观点,即在属性中插入XML文档作为词法XML是完全疯狂的。数据的所有者将失去如此多的权力和灵活性,并获得任何回报。但是,如果你真的别无选择,那就自杀(笑话)。如果此选项对您来说不合适,那么您可以使用类似的模板序列化内部XML ...

<xsl:template match="*" mode="serialise">
  <xsl:value-of select="concat('&lt;',local-name(),' ')">
  <xsl:apply-templates select="@*" mode="serialise">
  <xsl:value-of select="' &gt;'">
  <xsl:apply-templates select="*|text()" mode="serialise">
  <xsl:value-of select="concat('&lt;/',local-name(),' &gt;')">
</xsl:template>

<xsl:template match="@*" mode="serialise">
  <xsl:value-of select="concat(local-name(),'=&quot;',.,'&quot; ')">
</xsl:template>

<xsl:template match="text()" mode="serialise">
  <xsl:value-of select=".">
</xsl:template>

将要编码的内部结构的根元素作为词法XML并调用&lt; xsl:apply-templates&gt;使用@ mode =“serialise”。将此调用的输出捕获到字符串变量中。然后,您可以在您喜欢的结果树中的what-ever属性中插入字符串变量的内容。

买者

这些简单的模板不处理comments(),processing-instructions()和DocTypes。此外,根据XDM(与DOM相反),将合并相邻的文本类型节点(文本,CDATA,字符引用等)。这也不适用于名称空间。

答案 1 :(得分:3)

我可以节省自己的时间,努力和抑郁,避免别人的愚蠢,并通过一个使用微小扩展功能的微小转变实现这一点

以下是使用.NET XslCompiledTransform XSLT处理器的示例:

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

 <xsl:template match="/*">
  <t stupid="{my:stringize(.)}"/>
 </xsl:template>

 <msxsl:script language="c#" implements-prefix="my">
  public string stringize(XPathNavigator doc)
  {
   return doc.InnerXml;
  }
 </msxsl:script>
</xsl:stylesheet>

当应用于任何XML文档时,它会生成带有stupid属性的顶部元素,该属性包含顶部元素主体的转义表示。

例如,在此XML文档上应用转换时

<t>
  <a>
    <b x="y">
      <!--  Comment here -->
      <?aPI ?>
    </b>
  </a>
</t>

生成了想要的结果

<t stupid="&#xD;&#xA;  &lt;a&gt;&#xD;&#xA;    &lt;b x=&quot;y&quot;&gt;&#xD;&#xA;      &lt;!--  Comment here --&gt;&#xD;&#xA;      &lt;?aPI?&gt;&#xD;&#xA;    &lt;/b&gt;&#xD;&#xA;  &lt;/a&gt;&#xD;&#xA;" />

实现相同想法的转换最有可能为几乎每个XSLT处理器编写,其扩展函数本身可以用各种编程语言编写。

答案 2 :(得分:2)

可以在http://code.google.com/p/httpfox/source/browse/trunk/chrome/content/XMLPrettyPrint.xsl?r=3找到用于将XML序列化为转义文本的XSLT样式表。它输出HTML,但您可以轻松地将其调整为输出XML,主要是通过删除不需要的东西,如扩展器。

唯一棘手的部分可能是从现有XSL获取XML输出作为新模板的输入。如果将后者作为单独的样式表实现,或者如果使用XSLT 2.0,则没有问题。否则,您可能需要使用node-set()扩展功能。

以上几个方面可以详细说明。霍勒,如果你卡住了! HTH。

P.S。实际上,自从我开始这篇文章以来,@ Sean发布了他的答案,并且比使用上述样式表更容易使用。

答案 3 :(得分:2)

基本上,您需要序列化XML,将序列化的结果捕获为字符串,然后使用此字符串作为其值来编写属性。在XSLT 1.0或XSLT 2.0中没有直接的方法。 XSLT 3.0有一个函数fn:serialize(),旨在满足这一要求,并在最新版本的Saxon中实现。 (早期版本的Saxon使用saxon:serialize()扩展函数引入了这个想法。您可以在其他产品中找到类似的函数,或者您也可以编写自己的函数。)在XSLT中实现序列化程序当然是可能的,如其他人建议;它只是相当乏味。