【问题标题】:XSL Conversion XML->XML outputs only text?XSL 转换 XML->XML 仅输出文本?
【发布时间】:2009-05-10 11:00:43
【问题描述】:

您好,我有以下 XAML 代码,它是 XamlWriter.Save() 的输出:

<StackPanel Name="itemStack" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:mm="clr-namespace:MindManager;assembly=MindManager">
  <mm:Item Width="Auto" Height="Auto">
    <Border BorderThickness="10,10,10,10" Name="border1" Height="Auto">
      <DockPanel>
        <DockPanel LastChildFill="True" Name="dockPanel1" Height="33" DockPanel.Dock="Top">
          <Button Name="deleteItemButton" Width="26" Height="21.638" FlowDirection="LeftToRight" DockPanel.Dock="Right" Grid.IsSharedSizeScope="False">x</Button>
          <TextBox Name="tagsTextBox" Height="19">1</TextBox>
        </DockPanel>
        <TextBox TextWrapping="Wrap" MinLines="5" AcceptsReturn="True" AcceptsTab="True" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled" AutoWordSelection="True" Name="contentTextBox" Width="Auto" MinWidth="600" Height="Auto" MinHeight="80">2</TextBox>
      </DockPanel>
    </Border>
  </mm:Item>
  <mm:Item Width="Auto" Height="Auto">
    <Border BorderThickness="10,10,10,10" Name="border1" Height="Auto">
      <DockPanel>
        <DockPanel LastChildFill="True" Name="dockPanel1" Height="33" DockPanel.Dock="Top">
          <Button Name="deleteItemButton" Width="26" Height="21.638" FlowDirection="LeftToRight" DockPanel.Dock="Right" Grid.IsSharedSizeScope="False">x</Button>
          <TextBox Name="tagsTextBox" Height="19">3</TextBox>
        </DockPanel>
        <TextBox TextWrapping="Wrap" MinLines="5" AcceptsReturn="True" AcceptsTab="True" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled" AutoWordSelection="True" Name="contentTextBox" Width="Auto" MinWidth="600" Height="Auto" MinHeight="80">4</TextBox>
      </DockPanel>
    </Border>
  </mm:Item>
</StackPanel>

我想使用以下 XSL 将其转换为更简单的 XML:

<?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" xmlns:mm="clr-namespace:MindManager;assembly=MindManager">  
  <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/StackPanel">
      <mindcontainer>
        <xsl:for-each select="mm:Item">
          <minditem>
            <xsl:value-of select="/tagsTextBox"/>
            <xsl:value-of select="/contentTextBox"/>
          </minditem>
        </xsl:for-each>
      </mindcontainer>
    </xsl:template>
</xsl:stylesheet>

我希望输出具有以下格式:

<mindcontainer>
 <minditem>
   content of tagsTextBox
   content of contentTextBox
 </minditem>
 <minditem>
   content of tagsTextBox
   content of contentTextBox
 </minditem>
</mindcontainer>

但问题是我从中得到的只是:

  x
  1

2







  x
  3

4

可以看到只有文字,没有文字,过滤器也不起作用,x是我不想输出的关闭按钮的标签。

这是我用来执行转换的代码:

    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent=true;

    StringBuilder sb = new StringBuilder();
    using (XmlWriter wr = XmlWriter.Create(sb, settings))
    {
        XamlWriter.Save(scrollViewer1.Content, wr);
    }

    settings.ConformanceLevel = ConformanceLevel.Auto;
    using (XmlReader rd = XmlReader.Create(new StringReader(sb.ToString())))
    {
        XslCompiledTransform trans = new XslCompiledTransform();
        trans.Load("output.xsl");

        trans.Transform(rd, XmlWriter.Create("mindstore.xms", settings));
    }

【问题讨论】:

    标签: c# xml xaml xslt


    【解决方案1】:

    在 XPath/XSLT 1.0 中,要选择(或匹配)名称空间中的元素,您必须声明名称空间前缀并在表达式(或模式)中使用该前缀。不要被 &lt;StackPanel&gt; 和其他元素在输入 XML 中不使用前缀的事实所迷惑。它使用默认命名空间,由该默认命名空间声明确定:

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    

    所以你需要在你的样式表中有一个相应的声明(就像你对“mm”命名空间所做的那样),除了你需要选择一个命名空间前缀来使用。任何前缀都可以(就像您实际上不必使用“mm”一样)。

    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      ...>
    

    然后,在您的样式表中,您需要更新您的表达式和模式以使用您选择的前缀(在我上面的示例中为“x”):

    <xsl:template match="/x:StackPanel">
    

    您看到输出的原因是您的模板规则从未被调用(因为名称不匹配)。相反,会调用每个 XPath 节点类型的内置模板规则。对于根节点和元素节点,它只是继续处理子节点。对于文本节点,就是复制它们。因此,您看到的行为与任何空样式表(没有模板规则)的行为相同:输入文档中所有文本节点的转储。

    必须在每个表达式或模式中为每个名称测试添加前缀可能会很痛苦。这就是为什么 XSLT 2.0 引入了一个名为 xpath-default-namespace 的特性,它使得 XPath 表达式和 XSLT 模式可以使用默认名称空间,就像 XML 中的元素一样。在这种情况下,您只需添加一行即可:

    <xsl:stylesheet version="2.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xpath-default-namespace="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      ...>
    

    但这只是在您使用 XSLT 2.0 处理器的情况下。 (例如,MSXML 不支持 XSLT 2.0。)

    在我离开您之前,我在您的样式表中看到了更多问题(毫无疑问,您接下来会发现):

            <xsl:value-of select="/tagsTextBox"/>
            <xsl:value-of select="/contentTextBox"/>
    

    以“/”开头的表达式意味着“从文档/根节点开始”。所以这些表达式分别寻找&lt;tagsTextBox&gt; 文档元素和&lt;contentTextBox&gt; 文档元素。根据我在您的示例输入文档中看到的内容,我认为您的意思是:

            <xsl:value-of select=".//x:TextBox[@Name = 'tagsTextBox']"/>
            <xsl:value-of select=".//x:TextBox[@Name = 'contentTextBox']"/>
    

    希望这会有所帮助!如果有任何需要进一步解释的地方,请告诉我。

    【讨论】:

      【解决方案2】:

      您的问题至少在 XSLT 中:

      1. 您需要将匹配的表达式放在正确的命名空间中,因为它们要匹配。 例如

        ... xml:xaml='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
        <xsl:template match='/xaml:StackPanel'>...
        
      2. value-of 表达式(匹配 /tagsTextBox/contentText)Box 似乎旨在匹配 StackPanel,但是:

        • 也缺少命名空间限定
        • 匹配文档根的直接子节点,而不是后代节点 当前内容节点的。您可能需要:

          <xsl:value-of select='descendent::xaml:TextBox'/>
          

      可能还有更多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-12
        • 1970-01-01
        • 1970-01-01
        • 2017-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多