【问题标题】:Renaming XML nodes and replacing values with XSL重命名 XML 节点并用 XSL 替换值
【发布时间】:2014-01-28 09:52:25
【问题描述】:

我遇到了一个问题,没有任何东西被替换。

我查看了 rename nodesreplace values 的其他 SO 问题,并从答案中复制了示例,但对我没有任何帮助。我怀疑我有一些微妙的错误,但我查看了我的 C#、XML 和 XSL 代码,但似乎找不到。

这是我的 C# 代码:

private static string GetOutput(string xmlFileName, string xslFileName)
{
    var xmlDocument = new XmlDocument();
    xmlDocument.Load(xmlFileName);

    var xslTransform = new XslCompiledTransform();
    xslTransform.Load(xslFileName);

    var stream = new MemoryStream();
    xslTransform.Transform(xmlDocument, null, stream);

    stream.Position = 1;
    var reader = new StreamReader(stream);
    string output = reader.ReadToEnd();

    return output;
}

这是我的 XML 文件的内容:

<?xml version="1.0" encoding="utf-8" ?>
<TransformThis xmlns="http://schemas.datacontract.org/2004/07/TransformTest" 
             xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <f_name>John</f_name>
    <l_name>D&apos;Oh!</l_name>
    <Version>1.0</Version>
</TransformThis>

这是我的 XSL 文件的内容:

<?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">

    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="Version/text()[.='1.0']">1.1</xsl:template>

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

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

</xsl:stylesheet>

当我运行我的程序时,输出与原始 XML 相同。 f_name 和 l_name 节点都没有被重命名,Version 节点的值也没有被替换。

任何帮助将不胜感激。

更新根据下面 michael.hor257k 的回答,我已将我的 XLS 文件修改如下:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:tx="http://schemas.datacontract.org/2004/07/TransformTest"
                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="tx:Version/text()[.='1.0']">1.1</xsl:template>

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

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

</xsl:stylesheet>

我将 ...TransformTest 命名空间添加到 XLS 文件中,并在 match 节点前加上 tx:

现在转换正在工作,但它也将 tx: 命名空间添加到重命名的节点:

<?xml version="1.0" encoding="utf-8"?>
<Transformer xmlns="http://schemas.datacontract.org/2004/07/TransformTest" 
             xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <FirstName xmlns="" xmlns:tx="http://schemas.datacontract.org/2004/07/TransformTest">John</FirstName>
    <LastName xmlns="" xmlns:tx="http://schemas.datacontract.org/2004/07/TransformTest">Doh</LastName>
    <Version>1.1</Version>
</Transformer>

此外,当 XML 反序列化为对象时,LastName 和 FirstName 属性为空,我怀疑这与这些节点上的其他命名空间属性有关。

我希望输出看起来像原始 XML,但只更改名称和值。

UPDATE #2 michael.hor257k 添加:他的答案中的示例 XLS 文件。这解决了我的所有问题。

【问题讨论】:

    标签: xml c#-4.0 xslt


    【解决方案1】:

    f_name 和 l_name 节点都没有被重命名,也没有 版本节点值已被替换。

    这些元素是&lt;TransformThis&gt; 元素的子元素,它有自己的命名空间。您必须在样式表中声明此命名空间,为其分配前缀并在寻址元素或其后代时使用该前缀。


    添加:
    试试这个方法?请注意,这有点棘手,因为您实际上是将新子代添加到现有(复制的)父代中。这些新元素不会自动继承其养父母的命名空间,它们需要明确分配给它们。

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns="http://schemas.datacontract.org/2004/07/TransformTest"
    exclude-result-prefixes="ns">
    
    <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
    
    <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ns:Version/text()[.='1.0']">1.1</xsl:template>
    
    <xsl:template match="ns:f_name">
        <xsl:element name="FirstName" namespace="http://schemas.datacontract.org/2004/07/TransformTest">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="ns:l_name">
        <xsl:element name="LastName" namespace="http://schemas.datacontract.org/2004/07/TransformTest">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 谢谢,@Michael.hor257k。我知道我做错了某事。你能举个例子吗?
    • @Weltonv3.53 是否要在结果中保留原始命名空间?
    • 是的,如果可能的话。我做了一些实验,将 XML 文件的命名空间添加到 XSL,并在节点名称前加上前缀,它确实 替换了节点名称和值,但它也将命名空间添加到重命名的节点。然后,当我将 XML 反序列化为对象时,这些节点的值丢失了。理想情况下,我希望输出看起来像原始 XML,但只更改名称和值。
    • @Weltonv3.53 我在答案中添加了样式表。
    猜你喜欢
    • 1970-01-01
    • 2014-08-27
    • 2015-01-11
    • 2018-03-05
    • 2013-07-11
    • 2015-06-15
    • 1970-01-01
    • 1970-01-01
    • 2013-09-07
    相关资源
    最近更新 更多