如何从<?xml-stylesheet>节点中获取href属性值?

9
我们从供应商那里得到了一个XML文档,我们需要使用他们的样式表对其执行XSL转换,以便将生成的HTML转换为PDF。实际的样式表在XML文档中的定义的href属性中引用。有没有办法使用C#获取该URL?我不相信供应商不会更改URL,显然不想硬编码它。
完整的元素的XML文件开头如下:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="http://www.fakeurl.com/StyleSheet.xsl"?>
6个回答

4

作为处理指令,它可以包含任何内容,因此在形式上没有任何属性。但是,如果您知道存在“伪”属性,例如xml-stylesheet处理指令的情况,则可以使用处理指令的值构造单个元素的标记,并使用XML解析器解析该标记:

    XmlDocument doc = new XmlDocument();
    doc.Load(@"file.xml");
    XmlNode pi = doc.SelectSingleNode("processing-instruction('xml-stylesheet')");
    if (pi != null)
    {
        XmlElement piEl = (XmlElement)doc.ReadNode(XmlReader.Create(new StringReader("<pi " + pi.Value + "/>")));
        string href = piEl.GetAttribute("href");
        Console.WriteLine(href);
    }
    else
    {
        Console.WriteLine("No pi found.");
    }

谢谢。花了很长时间才弄清楚这些被称为“处理指令”,LINQ 对我来说仍然毫无意义! - Mmm

3

Linq to xml 代码:

XDocument xDoc = ...;

var cssUrlQuery = from node in xDoc.Nodes()
        where node.NodeType == XmlNodeType.ProcessingInstruction
        select Regex.Match(((XProcessingInstruction)node).Data, "href=\"(?<url>.*?)\"").Groups["url"].Value;

或者对象linq
var cssUrls = (from XmlNode childNode in doc.ChildNodes
                   where childNode.NodeType == XmlNodeType.ProcessingInstruction && childNode.Name == "xml-stylesheet"
                   select (XmlProcessingInstruction) childNode
                   into procNode select Regex.Match(procNode.Data, "href=\"(?<url>.*?)\"").Groups["url"].Value).ToList();

xDoc.XPathSelectElement()无法工作,因为它无法将XElement转换为XProcessingInstruction。


我更喜欢使用DOM或LinqToXml,但是我挖掘得越深,看起来这可能是唯一的选择。 - AJ.
是的,我也一直在苦苦挣扎。如果有办法将 ProcessingInstruction 视为 Element 来处理,那就更简单了。 - AJ.

3
您也可以使用XPath。假设您已经加载了源XML文档:
XmlProcessingInstruction instruction = doc.SelectSingleNode("//processing-instruction(\"xml-stylesheet\")") as XmlProcessingInstruction;
if (instruction != null) {
    Console.WriteLine(instruction.InnerText);
}

那就使用正则表达式解析 InnerText 吧。

3
使用此XPath表达式,您无需进行任何正则表达式操作:translate(substring-after(processing-instruction('xml-stylesheet'),'href='),'&quot;','')。该表达式可将XML处理指令中的样式表链接提取出来,并移除引号。 - Mads Hansen

2
要使用适当的XML解析器来查找值,您可以编写类似于以下内容的代码:

using(var xr = XmlReader.Create(input))
{
    while(xr.Read())
    {
        if(xr.NodeType == XmlNodeType.ProcessingInstruction && xr.Name == "xml-stylesheet")
        {
            string s = xr.Value;
            int i = s.IndexOf("href=\"") + 6;
            s = s.Substring(i, s.IndexOf('\"', i) - i);
            Console.WriteLine(s);
            break;
        }
    }
}

使用XmlReader方法时,请注意像IsStartElement这样的方法调用会导致读取器跳过处理指令,如果找到开始元素节点。我使用了一个单独的读取循环来解析处理指令,然后再解析元素节点作为解决方法。 - blazeline

1
private string _GetTemplateUrl(XDocument formXmlData) 
{
    var infopathInstruction = (XProcessingInstruction)formXmlData.Nodes().First(node => node.NodeType == XmlNodeType.ProcessingInstruction && ((XProcessingInstruction)node).Target == "mso-infoPathSolution");
    var instructionValueAsDoc = XDocument.Parse("<n " + infopathInstruction.Data + " />");
    return instructionValueAsDoc.Root.Attribute("href").Value;
}

一个人必须使用 xml-stylesheet 而不是 mso-infoPathSolution,但这样对我有效。它获取第一个元素并返回结果。 - testing

0

XmlProcessingInstruction stylesheet = doc.SelectSingleNode("processing-instruction('xml-stylesheet')") as XmlProcessingInstruction;

XmlProcessingInstruction stylesheet = doc.SelectSingleNode("processing-instruction('xml-stylesheet')") as XmlProcessingInstruction;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接