4

我对 XML 和 XSL 样式表还很陌生,我的任务是为我们的一个客户创建样式表。我已经创建了一个样式表,它以以下格式输出 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 输出并将其放在一个属性中,同时将 <、>、" 等转换为 < 、 > 、 " 等(不确定它们叫什么)。

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

提前致谢!

4

4 回答 4

4

我会从别人的愚蠢中节省自己的时间、精力和沮丧,并将通过一个使用微小扩展函数的微小转换来实现这一点

下面是使用 .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 处理器编写实现相同想法的转换,该扩展功能本身可以用各种编程语言编写。

于 2012-07-24T02:27:18.523 回答
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 的内部结构的根元素,并使用 @mode="serialise" 调用 <xsl:apply-templates>。将此调用的输出捕获到字符串变量中。然后,您可以将字符串变量的内容插入您喜欢的结果树中的任何属性中。

警告

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

于 2012-07-24T01:06:01.640 回答
2

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

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

上面有几个方面可以详细说明。如果你被卡住了,请大声喊叫!HTH。

PS实际上,自从我开始这篇文章以来,@Sean 发布了他的答案,它比改编上述样式表更容易使用。

于 2012-07-24T01:36:02.733 回答
2

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

于 2012-07-24T02:07:14.150 回答