我想将模板与基于名称end-with的元素匹配

时间:2013-05-17 18:24:27

标签: xml xslt

我花了很多时间试图解决这个问题,而失败并没有提供任何关于错误的线索。我正在尝试使用xslt进行项目。显然,我正在尝试使用2.0,这是来自VS 2012,c#fw 4.5

对于此测试,如果值为0,我想用任何内容替换任何xxxSK元素的值。

这适用于以下元素:,等等。

如果我将底部模板定位到“SK”,则会将其正确应用于所有模板。但我希望“结束”逻辑(或在此示例中为“包含”)。当我运行这个时,我在调用Transform()时得到一条无用的消息:

System.InvalidProgramException was unhandled
HResult=-2146233030
Message=Common Language Runtime detected an invalid program.
Source=System.Xml.Xsl.CompiledQuery.1
StackTrace:
   at <xsl:apply-templates>(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug}runtime, XPathNavigator )
   at Root(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug}runtime)
   at Execute(XmlQueryRuntime {urn:schemas-microsoft-com:xslt-debug}runtime)
   at System.Xml.Xsl.XmlILCommand.Execute(Object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlSequenceWriter results)
   at System.Xml.Xsl.XmlILCommand.Execute(Object defaultDocument, XmlResolver dataSources, XsltArgumentList argumentList, XmlWriter writer)
   at System.Xml.Xsl.XslCompiledTransform.Transform(IXPathNavigable input, XsltArgumentList arguments, XmlWriter results, XmlResolver documentResolver)
   at System.Xml.Xsl.XslCompiledTransform.Transform(IXPathNavigable input, XsltArgumentList arguments, Stream results)
   at Test.XsltTest.Test(Drug drug, String styleSheet) in c:\DEV\Local Projects\_JunkTempWork\AppToSQLDataTransferTesting\Test\XsltTest.cs:line 34
   at Test.Program.Main(String[] args) in c:\DEV\Local Projects\_JunkTempWork\AppToSQLDataTransferTesting\Test\Program.cs:line 28
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
InnerException: 

[这里有一个类似的问题] [1],但我无法得到那个为我工作的答案。

这是我的样式表:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.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="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*[matches(name(), '.*SK')]">  <--- ORIGINAL QUESTION
<xsl:template match="*[substring(name(), string-length() -1) = 'SK']" priority="9"> <--- NEW BASED ON ANSWER

<xsl:text disable-output-escaping="yes">&lt;New</xsl:text><xsl:value-of select="name(.)"/>        <xsl:text disable-output-escaping="yes">&gt;</xsl:text>

  <xsl:if test=". != '0'">
    <xsl:value-of select="."/>
  </xsl:if>

<xsl:text disable-output-escaping="yes">&lt;/New</xsl:text><xsl:value-of select="name(.)"/><xsl:text disable-output-escaping="yes">&gt;</xsl:text>

  </xsl:template>
</xsl:stylesheet>

这是我的测试代码(模型只是一个简单的测试类):

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Serialization;
using Test.Models;
using System.Xml;
using System.Xml.Xsl;

namespace Test
{
    public class XsltTest
    {
        public string Test(Drug drug, string styleSheet)
        {
            //ListResources(); return string.Empty;

            // Serialize
            Console.WriteLine("Serialized:");
            string xml = XmlSerialization.Serialize(drug);

            // Load into XML DOC
            var xd = new XmlDocument();
            xd.LoadXml(xml);

            // Load XSLT DOC
            var xslt = GetTransform(styleSheet);

            using (var stm = new MemoryStream())
            {
                // Transform!
                xslt.Transform(xd, null, stm);

                // Fetch the results
                stm.Position = 1;
                using (var sr = new StreamReader(stm))
                {
                    string result = "\nSource:\n\n" + xml + "\n\nOutput:\n\n" + sr.ReadToEnd();
                    return result;
                }
            }


        }

        private void ListResources()
        {
            string[] resources = Assembly.GetExecutingAssembly().GetManifestResourceNames();
            foreach (string r in resources)
                Console.WriteLine("Resource: {0}", r);
        }

        private XslCompiledTransform GetTransform(string styleSheet)
        {
            if (!Assembly.GetExecutingAssembly().GetManifestResourceNames().Contains(styleSheet))
                throw new Exception(string.Format("Stylesheet {0} not found.", styleSheet));

            using (Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(styleSheet))
            {
                using (XmlReader reader = XmlReader.Create(s))
                {
                    XslCompiledTransform transform = new XslCompiledTransform();
                    transform.Load(reader);
                    return transform;
                }
            }
        }

    }
}

更新:感谢回复,我得到了部分工作。任何人都可以看到它为什么不匹配所有元素?正如你所看到的那样,它只与2个元素相匹配,即便如此,我也看不出它选择这些元素的原因,而不是其他元素。

输入XML:

<?xml version="1.0" encoding="utf-16"?>
<Drug xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <SK>0</SK>
  <MasterSK>0</MasterSK>
  <Name>Sample Drug Name</Name>
  <DrugRoutes>
    <DrugRoute>
      <SK>202</SK>
      <Name>Intravenous</Name>
    </DrugRoute>
    <DrugRoute>
      <SK>203</SK>
      <Name>Oral</Name>
    </DrugRoute>
    <DrugRoute>
      <SK>0</SK>
      <Name>New Route</Name>
    </DrugRoute>
  </DrugRoutes>
  <Flavor>Watermelon</Flavor>
</Drug>

结果(由于某种原因,它失去了格式,显然基于我所做的事情):

??<?xml version="1.0" encoding="utf-8"?>
<Drug xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><NewSK>NULL</NewSK><MasterSK>0</MasterSK><Name>Sample Drug Name</Name><DrugRoutes><DrugRoute><S
K>202</SK><Name>Intravenous</Name></DrugRoute><DrugRoute><SK>203</SK><Name>Oral</Name></DrugRoute><DrugRoute><NewSK>NULL</NewSK><Name>New Route</Name></DrugRoute></DrugRoutes><Flavor>Watermelon</Flavo
r></Drug>

1 个答案:

答案 0 :(得分:2)

因此,如果我理解正确,如果名称以“SK”结尾的元素的值为0,则您希望用新值替换其内容。那是对的吗?如果是这样,这样就可以了:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[. = '0']
                        [substring(name(), string-length(name()) -1) = 'SK']">
    <xsl:copy>
      <xsl:text>This used to be 0</xsl:text>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

在样本输入上运行时,结果为:

<Drug xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <SK>This used to be 0</SK>
  <MasterSK>This used to be 0</MasterSK>
  <Name>Sample Drug Name</Name>
  <DrugRoutes>
    <DrugRoute>
      <SK>202</SK>
      <Name>Intravenous</Name>
    </DrugRoute>
    <DrugRoute>
      <SK>203</SK>
      <Name>Oral</Name>
    </DrugRoute>
    <DrugRoute>
      <SK>This used to be 0</SK>
      <Name>New Route</Name>
    </DrugRoute>
  </DrugRoutes>
  <Flavor>Watermelon</Flavor>
</Drug>

看起来你在尝试更改元素名称时正在做一些hacky东西,但如果你想用新名称替换元素,你可以这样做:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[. = '0']
                        [substring(name(), string-length(name()) -1) = 'SK']">
    <xsl:element name="New{name()}">
      <xsl:text>This used to be 0</xsl:text>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

这导致:

<Drug xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <NewSK>This used to be 0</NewSK>
  <NewMasterSK>This used to be 0</NewMasterSK>
  <Name>Sample Drug Name</Name>
  <DrugRoutes>
    <DrugRoute>
      <SK>202</SK>
      <Name>Intravenous</Name>
    </DrugRoute>
    <DrugRoute>
      <SK>203</SK>
      <Name>Oral</Name>
    </DrugRoute>
    <DrugRoute>
      <NewSK>This used to be 0</NewSK>
      <Name>New Route</Name>
    </DrugRoute>
  </DrugRoutes>
  <Flavor>Watermelon</Flavor>
</Drug>