From c652822d35c98340d9db33ac10b1be6b39a1b193 Mon Sep 17 00:00:00 2001 From: jameshkramer Date: Fri, 5 Jun 2020 17:08:27 -0700 Subject: [PATCH 1/2] 43). Add topic files 135 to 138 --- .openpublishing.redirection.json | 42 +- ...-serialize-using-datacontractserializer.md | 86 --- .../how-to-serialize-using-xmlserializer.md | 84 --- .../concepts/linq/linq-to-xml-security.md | 98 --- .../concepts/linq/reference-linq-to-xml.md | 18 - ...s-terminology-functional-transformation.md | 2 +- docs/standard/linq/linq-xml-axes-overview.md | 2 +- docs/standard/linq/linq-xml-security.md | 105 +++ .../linq/linq-xml-vs-xml-technologies.md | 2 +- .../mixed-declarative-imperative-code-bugs.md | 247 +++++++ docs/standard/linq/namespaces-overview.md | 2 +- ...streaming-transform-large-xml-documents.md | 586 ++++++++++++++++ docs/standard/linq/reference.md | 20 + .../linq/serialize-datacontractserializer.md | 150 ++++ docs/standard/linq/serialize-xmlserializer.md | 145 ++++ ...xml-fragments-access-header-information.md | 299 ++++++++ ...ons-transform-linq-xml-trees-xslt-style.md | 645 ++++++++++++++++++ .../linq/use-xslt-transform-xml-tree.md | 120 ++++ .../xml-shape-wordprocessingml-documents.md | 4 +- ...-serialize-using-datacontractserializer.md | 82 --- .../how-to-serialize-using-xmlserializer.md | 79 --- .../concepts/linq/linq-to-xml-security.md | 98 --- .../concepts/linq/reference-linq-to-xml.md | 18 - 23 files changed, 2364 insertions(+), 570 deletions(-) delete mode 100644 docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md delete mode 100644 docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md delete mode 100644 docs/csharp/programming-guide/concepts/linq/linq-to-xml-security.md delete mode 100644 docs/csharp/programming-guide/concepts/linq/reference-linq-to-xml.md create mode 100644 docs/standard/linq/linq-xml-security.md create mode 100644 docs/standard/linq/mixed-declarative-imperative-code-bugs.md create mode 100644 docs/standard/linq/perform-streaming-transform-large-xml-documents.md create mode 100644 docs/standard/linq/reference.md create mode 100644 docs/standard/linq/serialize-datacontractserializer.md create mode 100644 docs/standard/linq/serialize-xmlserializer.md create mode 100644 docs/standard/linq/stream-xml-fragments-access-header-information.md create mode 100644 docs/standard/linq/use-annotations-transform-linq-xml-trees-xslt-style.md create mode 100644 docs/standard/linq/use-xslt-transform-xml-tree.md delete mode 100644 docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md delete mode 100644 docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md delete mode 100644 docs/visual-basic/programming-guide/concepts/linq/linq-to-xml-security.md delete mode 100644 docs/visual-basic/programming-guide/concepts/linq/reference-linq-to-xml.md diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 3914427e8f5eb..a28d899f664a4 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1924,7 +1924,27 @@ "redirect_url": "/dotnet/standard/linq/retrieve-text-paragraphs", "redirect_document_id": true }, - { + { + "source_path": "docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md", + "redirect_url": "/dotnet/standard/linq/serialize-datacontractserializer", + "redirect_document_id": true + }, + { + "source_path": "docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md", + "redirect_url": "/dotnet/standard/linq/serialize-xmlserializer", + "redirect_document_id": true + }, + { + "source_path": "docs/csharp/programming-guide/concepts/linq/linq-to-xml-security.md", + "redirect_url": "/dotnet/standard/linq/linq-xml-security", + "redirect_document_id": true + }, + { + "source_path": "docs/csharp/programming-guide/concepts/linq/reference-linq-to-xml.md", + "redirect_url": "/dotnet/standard/linq/reference", + "redirect_document_id": true + }, + { "source_path": "docs/csharp/programming-guide/concepts/threading/how-to-use-a-thread-pool.md", "redirect_url": "/dotnet/api/system.threading.threadpool.queueuserworkitem" }, @@ -5511,6 +5531,26 @@ "redirect_url": "/dotnet/standard/linq/retrieve-text-paragraphs", "redirect_document_id": false }, + { + "source_path": "docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md", + "redirect_url": "/dotnet/standard/linq/serialize-datacontractserializer", + "redirect_document_id": false + }, + { + "source_path": "docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md", + "redirect_url": "/dotnet/standard/linq/serialize-xmlserializer", + "redirect_document_id": false + }, + { + "source_path": "docs/visual-basic/programming-guide/concepts/linq/linq-to-xml-security.md", + "redirect_url": "/dotnet/standard/linq/linq-xml-security", + "redirect_document_id": false + }, + { + "source_path": "docs/visual-basic/programming-guide/concepts/linq/reference-linq-to-xml.md", + "redirect_url": "/dotnet/standard/linq/reference", + "redirect_document_id": false + }, { "source_path": "docs/visual-basic/programming-guide/concepts/threading/how-to-use-a-thread-pool.md", "redirect_url": "/dotnet/api/system.threading.threadpool.queueuserworkitem" diff --git a/docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md b/docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md deleted file mode 100644 index db924b9fdb9d5..0000000000000 --- a/docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: "How to serialize using DataContractSerializer (C#)" -ms.date: 07/20/2015 -ms.assetid: 3320ecbf-cdbe-480e-979c-2c14bbef9988 ---- -# How to serialize using DataContractSerializer (C#) -This topic shows an example that serializes and deserializes using . - -## Example - The following example creates a number of objects that contain objects. It then serializes them to text files, and then deserializes them from the text files. - -```csharp -using System; -using System.Xml; -using System.Xml.Linq; -using System.IO; -using System.Runtime.Serialization; - -public class XLinqTest -{ - public static void Main() - { - Test(CreateXElement()); - Test(new XElementContainer()); - Test(new XElementNullContainer()); - } - - public static void Test(T obj) - { - DataContractSerializer s = new DataContractSerializer(typeof(T)); - using (FileStream fs = File.Open("test" + typeof(T).Name + ".xml", FileMode.Create)) - { - Console.WriteLine("Testing for type: {0}", typeof(T)); - s.WriteObject(fs, obj); - } - using (FileStream fs = File.Open("test" + typeof(T).Name + ".xml", FileMode.Open)) - { - object s2 = s.ReadObject(fs); - if (s2 == null) - Console.WriteLine(" Deserialized object is null (Nothing in VB)"); - else - Console.WriteLine(" Deserialized type: {0}", s2.GetType()); - } - } - - public static XElement CreateXElement() - { - return new XElement(XName.Get("NameInNamespace", "http://www.adventure-works.org")); - } -} - -[DataContract] -public class XElementContainer -{ - [DataMember] - public XElement member; - - public XElementContainer() - { - member = XLinqTest.CreateXElement(); - } -} - -[DataContract] -public class XElementNullContainer -{ - [DataMember] - public XElement member; - - public XElementNullContainer() - { - member = null; - } -} -``` - - This example produces the following output: - -```output -Testing for type: System.Xml.Linq.XElement - Deserialized type: System.Xml.Linq.XElement -Testing for type: XElementContainer - Deserialized type: XElementContainer -Testing for type: XElementNullContainer - Deserialized type: XElementNullContainer -``` diff --git a/docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md b/docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md deleted file mode 100644 index e97a370d26078..0000000000000 --- a/docs/csharp/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: "How to serialize using XmlSerializer (C#)" -ms.date: 07/20/2015 -ms.assetid: 2e0a0bbc-c548-4fe2-8741-be5a9ccd0cbb ---- -# How to serialize using XmlSerializer (C#) -This topic shows an example that serializes and deserializes using . - -## Example - The following example creates a number of objects that contain objects. It then serializes them to a memory stream, and then deserializes them from the memory stream. - -```csharp -using System; -using System.IO; -using System.Linq; -using System.Xml; -using System.Xml.Serialization; -using System.Xml.Linq; - -public class XElementContainer -{ - public XElement member; - - public XElementContainer() - { - member = XLinqTest.CreateXElement(); - } - - public override string ToString() - { - return member.ToString(); - } -} - -public class XElementNullContainer -{ - public XElement member; - - public XElementNullContainer() - { - } -} - -class XLinqTest -{ - static void Main(string[] args) - { - Test(new XElementNullContainer()); - Test(CreateXElement()); - Test(new XElementContainer()); - } - - public static XElement CreateXElement() - { - XNamespace ns = "http://www.adventure-works.com"; - return new XElement(ns + "aw"); - } - - static void Test(T obj) - { - using (MemoryStream stream = new MemoryStream()) - { - XmlSerializer s = new XmlSerializer(typeof(T)); - Console.WriteLine("Testing for type: {0}", typeof(T)); - s.Serialize(XmlWriter.Create(stream), obj); - stream.Flush(); - stream.Seek(0, SeekOrigin.Begin); - object o = s.Deserialize(XmlReader.Create(stream)); - Console.WriteLine(" Deserialized type: {0}", o.GetType()); - } - } -} -``` - - This example produces the following output: - -```output -Testing for type: XElementNullContainer - Deserialized type: XElementNullContainer -Testing for type: System.Xml.Linq.XElement - Deserialized type: System.Xml.Linq.XElement -Testing for type: XElementContainer - Deserialized type: XElementContainer -``` diff --git a/docs/csharp/programming-guide/concepts/linq/linq-to-xml-security.md b/docs/csharp/programming-guide/concepts/linq/linq-to-xml-security.md deleted file mode 100644 index 49d755d4ffd5e..0000000000000 --- a/docs/csharp/programming-guide/concepts/linq/linq-to-xml-security.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: "LINQ to XML Security (C#)" -ms.date: 07/20/2015 -ms.assetid: ef2c0dc9-ecf9-4c17-b24e-144184ab725f ---- -# LINQ to XML Security (C#) -This topic describes security issues associated with LINQ to XML. In addition, it provides some guidance for mitigating security exposure. - -## LINQ to XML Security Overview - LINQ to XML is designed more for programming convenience than for server-side applications with stringent security requirements. Most XML scenarios consist of processing trusted XML documents, rather than processing untrusted XML documents that are uploaded to a server. LINQ to XML is optimized for these scenarios. - - If you must process untrusted data from unknown sources, Microsoft recommends that you use an instance of the class that has been configured to filter out known XML denial of service (DoS) attacks. - - If you have configured an to mitigate denial of service attacks, you can use that reader to populate a LINQ to XML tree and still benefit from the programmer productivity enhancements of LINQ to XML. Many mitigation techniques involve creating readers that are configured to mitigate the security issue, and then instantiating an XML tree through the configured reader. - - XML is intrinsically vulnerable to denial of service attacks because documents are unbounded in size, depth, element name size, and more. Regardless of the component that you use to process XML, you should always be prepared to recycle the application domain if it uses excessive resources. - -## Mitigation of XML, XSD, XPath, and XSLT Attacks - LINQ to XML is built upon and . LINQ to XML supports XSD and XPath through extension methods in the and namespaces. Using the , , and classes in conjunction with LINQ to XML, you can invoke XSLT to transform XML trees. - - If you are operating in a less secure environment, there are a number of security issues that are associated with XML and the use of the classes in , , , and . These issues include, but are not limited to, the following: - -- XSD, XPath, and XSLT are string-based languages in which you can specify operations that consume a lot of time or memory. It is the responsibility of application programmers who take XSD, XPath, or XSLT strings from untrusted sources to validate that the strings are not malicious, or to monitor and mitigate the possibility that evaluating these strings will lead to excessive system resource consumption. - -- XSD schemas (including inline schemas) are inherently vulnerable to denial of service attacks; you should not accept schemas from untrusted sources. - -- XSD and XSLT can include references to other files, and such references can result in cross-zone and cross-domain attacks. - -- External entities in DTDs can result in cross-zone and cross-domain attacks. - -- DTDs are vulnerable to denial of service attacks. - -- Exceptionally deep XML documents can pose denial of service issues; you might want to limit the depth of XML documents. - -- Do not accept supporting components, such as , , and objects, from untrusted assemblies. - -- Read data in chunks to mitigate large document attacks. - -- Script blocks in XSLT style sheets can expose a number of attacks. - -- Validate carefully before constructing dynamic XPath expressions. - -## LINQ to XML Security Issues - The security issues in this topic are not presented in any particular order. All issues are important and should be addressed as appropriate. - - A successful elevation of privilege attack gives a malicious assembly more control over its environment. A successful elevation of privilege attack can result in disclosure of data, denial of service, and more. - - Applications should not disclose data to users who are not authorized to see that data. - - Denial of service attacks cause the XML parser or LINQ to XML to consume excessive amounts of memory or CPU time. Denial of service attacks are considered to be less severe than elevation of privilege attacks or disclosure of data attacks. However, they are important in a scenario where a server needs to process XML documents from untrusted sources. - -### Exceptions and Error Messages Might Reveal Data - The description of an error might reveal data, such as the data being transformed, file names, or implementation details. Error messages should not be exposed to callers that are not trusted. You should catch all errors and report errors with your own custom error messages. - -### Do Not Call CodeAccessPermissions.Assert in an Event Handler - An assembly can have lesser or greater permissions. An assembly that has greater permissions has greater control over the computer and its environments. - - If code in an assembly with greater permissions calls in an event handler, and then the XML tree is passed to a malicious assembly that has restricted permissions, the malicious assembly can cause an event to be raised. Because the event runs code that is in the assembly with greater permissions, the malicious assembly would then be operating with elevated privileges. - - Microsoft recommends that you never call in an event handler. - -### DTDs are Not Secure - Entities in DTDs are inherently not secure. It is possible for a malicious XML document that contains a DTD to cause the parser to use all memory and CPU time, causing a denial of service attack. Therefore, in LINQ to XML, DTD processing is turned off by default. You should not accept DTDs from untrusted sources. - - One example of accepting DTDs from untrusted sources is a Web application that allows Web users to upload an XML file that references a DTD and a DTD file. Upon validation of the file, a malicious DTD could execute a denial of service attack on your server. Another example of accepting DTDs from untrusted sources is to reference a DTD on a network share that also allows anonymous FTP access. - -### Avoid Excessive Buffer Allocation - Application developers should be aware that extremely large data sources can lead to resource exhaustion and denial of service attacks. - - If a malicious user submits or uploads a very large XML document, it could cause LINQ to XML to consume excessive system resources. This can constitute a denial of service attack. To prevent this, you can set the property, and create a reader that is then limited in the size of document that it can load. You then use the reader to create the XML tree. - - For example, if you know that the maximum expected size of your XML documents coming from an untrusted source will be less than 50K bytes, set to 100,000. This will not encumber your processing of XML documents, and at the same time it will mitigate denial of service threats where documents might be uploaded that would consume large amounts of memory. - -### Avoid Excess Entity Expansion - One of the known denial of service attacks when using a DTD is a document that causes excessive entity expansion. To prevent this, you can set the property, and create a reader that is then limited in the number of characters that result from entity expansion. You then use the reader to create the XML tree. - -### Limit the Depth of the XML Hierarchy - One possible denial of service attack is when a document is submitted that has excessive depth of hierarchy. To prevent this, you can wrap a in your own class that counts the depth of elements. If the depth exceeds a predetermined reasonable level, you can terminate the processing of the malicious document. - -### Protect Against Untrusted XmlReader or XmlWriter Implementations - Administrators should verify that any externally supplied or implementations have strong names and have been registered in the machine configuration. This prevents malicious code masquerading as a reader or writer from being loaded. - -### Periodically Free Objects that Reference XName - To protect against certain kinds of attacks, application programmers should free all objects that reference an object in the application domain on a regular basis. - -### Protect Against Random XML Names - Applications that take data from untrusted sources should consider using an that is wrapped in custom code to inspect for the possibility of random XML names and namespaces. If such random XML names and namespaces are detected, the application can then terminate the processing of the malicious document. - - You might want to limit the number of names in any given namespace (including names in no namespace) to a reasonable limit. - -### Annotations Are Accessible by Software Components that Share a LINQ to XML Tree - LINQ to XML could be used to build processing pipelines in which different application components load, validate, query, transform, update, and save XML data that is passed between components as XML trees. This can help optimize performance, because the overhead of loading and serializing objects to XML text is done only at the ends of the pipeline. Developers must be aware, however, that all annotations and event handlers created by one component are accessible to other components. This can create a number of vulnerabilities if the components have different levels of trust. To build secure pipelines across less trusted components, you must serialize LINQ to XML objects to XML text before passing the data to an untrusted component. - - Some security is provided by the common language runtime (CLR). For example, a component that does not include a private class cannot access annotations keyed by that class. However, annotations can be deleted by components that cannot read them. This could be used as a tampering attack. - -## See also - -- [Programming Guide (LINQ to XML) (C#)](linq-to-xml-overview.md) diff --git a/docs/csharp/programming-guide/concepts/linq/reference-linq-to-xml.md b/docs/csharp/programming-guide/concepts/linq/reference-linq-to-xml.md deleted file mode 100644 index 94600e362a2f6..0000000000000 --- a/docs/csharp/programming-guide/concepts/linq/reference-linq-to-xml.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "Reference (LINQ to XML)" -ms.date: 07/20/2015 -ms.assetid: 815b45e2-3527-4dee-9986-b1277a693cde ---- -# Reference (LINQ to XML) -This topic contains links to the LINQ to XML reference topics. - -## In This Section - For reference documentation for the LINQ to XML classes, see . - - For reference documentation for the extension methods that help you validate XML trees against an XSD file, see . - - For reference documentation for the extension methods that enable you to evaluate XPath queries on an XML tree, see . - -## See also - -- [LINQ to XML (C#)](./linq-to-xml-overview.md) diff --git a/docs/standard/linq/concepts-terminology-functional-transformation.md b/docs/standard/linq/concepts-terminology-functional-transformation.md index 060b93181dca0..417c02a2ec222 100644 --- a/docs/standard/linq/concepts-terminology-functional-transformation.md +++ b/docs/standard/linq/concepts-terminology-functional-transformation.md @@ -23,7 +23,7 @@ In *pure functional transformation*, a set of functions, called *pure functions* > > Note that pure functions must be implemented as methods in C#, and as functions in Visual Basic. > -> You should not confuse pure functions with pure virtual methods in C++. The latter indicates that the containing class is abstract and that no method body is supplied. +> You shouldn't confuse pure functions with pure virtual methods in C++. The latter indicates that the containing class is abstract and that no method body is supplied. ### Functional programming diff --git a/docs/standard/linq/linq-xml-axes-overview.md b/docs/standard/linq/linq-xml-axes-overview.md index 79918f181d54d..269cea529107d 100644 --- a/docs/standard/linq/linq-xml-axes-overview.md +++ b/docs/standard/linq/linq-xml-axes-overview.md @@ -6,7 +6,7 @@ ms.assetid: 516792fb-461d-40a8-8a50-9993a51258fc --- # LINQ to XML axes overview -After you have created an XML tree or loaded an XML document into an XML tree, you can query it to find elements and attributes and retrieve their values. You retrieve collections through the *axis methods*, also called *axes*. Some of the axes are methods in the and classes that return collections. Some of the axes are extension methods in the class. The axes that are implemented as extension methods operate on collections, and return collections. +After you've created an XML tree or loaded an XML document into an XML tree, you can query it to find elements and attributes and retrieve their values. You retrieve collections through the *axis methods*, also called *axes*. Some of the axes are methods in the and classes that return collections. Some of the axes are extension methods in the class. The axes that are implemented as extension methods operate on collections, and return collections. As described in [XElement class overview](xelement-class-overview.md), an object represents a single element node. The content of an element can be complex (sometimes called structured content), or it can be a simple element. A simple element can be empty or can contain a value. If the node contains structured content, you can use the various axis methods to retrieve enumerations of descendant elements. The most commonly used axis methods are and . diff --git a/docs/standard/linq/linq-xml-security.md b/docs/standard/linq/linq-xml-security.md new file mode 100644 index 0000000000000..52cb4dffdcf2c --- /dev/null +++ b/docs/standard/linq/linq-xml-security.md @@ -0,0 +1,105 @@ +--- +title: LINQ to XML Security - LINQ to XML +description: Learn about LINQ to XML security issues, and ways to mitigate security exposure. +ms.date: 07/20/2015 +ms.assetid: ef2c0dc9-ecf9-4c17-b24e-144184ab725f +--- + +# LINQ to XML security + +This article describes security issues associated with LINQ to XML, and provides guidance for mitigating security exposure. + +## LINQ to XML security overview + +LINQ to XML is designed more for programming convenience than for server-side applications with stringent security requirements. Most XML scenarios consist of processing trusted XML documents, rather than processing untrusted XML documents that are uploaded to a server. LINQ to XML is optimized for these scenarios. + +If you must process untrusted data from unknown sources, Microsoft recommends that you use an instance of the class that has been configured to filter out known XML denial of service (DoS) attacks. + +If you've configured an to mitigate denial of service attacks, you can use that reader to populate a LINQ to XML tree and still benefit from the programmer productivity enhancements of LINQ to XML. Many mitigation techniques involve creating readers that are configured to mitigate the security issue, and then instantiating an XML tree through the configured reader. + +XML is intrinsically vulnerable to denial of service attacks because documents are unbounded in size, depth, element name size, and more. Regardless of the component that you use to process XML, you should always be prepared to recycle the application domain if it uses excessive resources. + +## Mitigation of XML, XSD, XPath, and XSLT attacks + +LINQ to XML is built upon and . LINQ to XML supports XSD and XPath through extension methods in the and namespaces. By using the , , and classes in conjunction with LINQ to XML, you can invoke XSLT to transform XML trees. + +If you're operating in a less secure environment, there are a number of security issues that are associated with XML and the use of the classes in , , , and . These issues include, but aren't limited to, the following: + +- XSD, XPath, and XSLT are string-based languages in which you can specify operations that consume a lot of time or memory. It's the responsibility of application programmers who take XSD, XPath, or XSLT strings from untrusted sources to validate that the strings aren't malicious, or to monitor and mitigate the possibility that evaluating these strings will lead to excessive system resource consumption. +- XSD schemas (including inline schemas) are inherently vulnerable to denial of service attacks; you shouldn't accept schemas from untrusted sources. +- XSD and XSLT can include references to other files, and such references can result in cross-zone and cross-domain attacks. +- External entities in DTDs can result in cross-zone and cross-domain attacks. +- DTDs are vulnerable to denial of service attacks. +- Exceptionally deep XML documents can pose denial of service issues; you might want to limit the depth of XML documents. +- Don't accept supporting components, such as , , and objects, from untrusted assemblies. +- Read data in chunks to mitigate large document attacks. +- Script blocks in XSLT style sheets can expose a number of attacks. +- Validate carefully before constructing dynamic XPath expressions. + +## LINQ to XML security issues + +The security issues in this article aren't presented in any particular order. All issues are important and should be addressed as appropriate. + +A successful elevation of privilege attack gives a malicious assembly more control over its environment. A successful elevation of privilege attack can result in disclosure of data, denial of service, and more. + +Applications shouldn't disclose data to users who aren't authorized to see that data. + +Denial of service attacks cause the XML parser or LINQ to XML to consume excessive amounts of memory or CPU time. Denial of service attacks are considered to be less severe than elevation of privilege attacks or disclosure of data attacks. However, they're important in a scenario where a server needs to process XML documents from untrusted sources. + +### Don't expose error messages to untrusted callers + +The description of an error might reveal data, such as the data being transformed, file names, or implementation details. Error messages shouldn't be exposed to callers that aren't trusted. You should catch all errors and report errors with your own custom error messages. + +### Don't call CodeAccessPermissions.Assert in an event handler + +An assembly can have lesser or greater permissions. An assembly that has greater permissions has greater control over the computer and its environments. + +If code in an assembly with greater permissions calls in an event handler, and then the XML tree is passed to a malicious assembly that has restricted permissions, the malicious assembly can cause an event to be raised. Because the event runs code that's in the assembly with greater permissions, the malicious assembly would then be operating with elevated privileges. + +Microsoft recommends that you never call in an event handler. + +### Don't accept DTDs from untrusted sources + +Entities in DTDs are inherently not secure. It's possible for a malicious XML document that contains a DTD to cause the parser to use all memory and CPU time, causing a denial of service attack. Therefore, in LINQ to XML, DTD processing is turned off by default. You shouldn't accept DTDs from untrusted sources. + +One example of accepting DTDs from untrusted sources is a Web application that allows Web users to upload an XML file that references a DTD and a DTD file. Upon validation of the file, a malicious DTD could execute a denial of service attack on your server. Another example of accepting DTDs from untrusted sources is to reference a DTD on a network share that also allows anonymous FTP access. + +### Avoid excessive buffer allocation + +Application developers should be aware that extremely large data sources can lead to resource exhaustion and denial of service attacks. + +If a malicious user submits or uploads a very large XML document, it could cause LINQ to XML to consume excessive system resources. This can constitute a denial of service attack. To prevent this, you can set the property, and create a reader that's then limited in the size of document that it can load. You then use the reader to create the XML tree. + +For example, if you know that the maximum expected size of your XML documents coming from an untrusted source will be less than 50K bytes, set to 100,000. This will not encumber your processing of XML documents, and at the same time it will mitigate denial of service threats where documents might be uploaded that would consume large amounts of memory. + +### Avoid excess entity expansion + +One of the known denial of service attacks when using a DTD is a document that causes excessive entity expansion. To prevent this, you can set the property, and create a reader that's then limited in the number of characters that result from entity expansion. You then use the reader to create the XML tree. + +### Limit the depth of the XML hierarchy + +One possible denial of service attack is when a document is submitted that has excessive depth of hierarchy. To prevent this, you can wrap an in your own class that counts the depth of elements. If the depth exceeds a predetermined reasonable level, you can terminate the processing of the malicious document. + +### Protect against untrusted XmlReader or XmlWriter implementations + +Administrators should verify that any externally supplied or implementations have strong names and have been registered in the machine configuration. This prevents malicious code masquerading as a reader or writer from being loaded. + +### Periodically free objects that reference XName + +To protect against certain kinds of attacks, application programmers should free all objects that reference an object in the application domain on a regular basis. + +### Protect against random XML names + +Applications that take data from untrusted sources should consider using an that's wrapped in custom code to inspect for the possibility of random XML names and namespaces. If such random XML names and namespaces are detected, the application can then terminate the processing of the malicious document. + +You might want to limit the number of names in any given namespace (including names in no namespace) to a reasonable limit. + +### Serialize LINQ to XML objects to XML text before passing the data to an untrusted component + +LINQ to XML could be used to build processing pipelines in which different application components load, validate, query, transform, update, and save XML data that's passed between components as XML trees. This can help optimize performance, because the overhead of loading and serializing objects to XML text is done only at the ends of the pipeline. Developers must be aware, however, that all annotations and event handlers created by one component are accessible to other components. This can create a number of vulnerabilities if the components have different levels of trust. To build secure pipelines across less trusted components, you must serialize LINQ to XML objects to XML text before passing the data to an untrusted component. + +Some security is provided by the common language runtime (CLR). For example, a component that doesn't include a private class can't access annotations keyed by that class. However, annotations can be deleted by components that can't read them. This could be used as a tampering attack. + +## See also + +- [LINQ to XML overview](linq-xml-overview.md) diff --git a/docs/standard/linq/linq-xml-vs-xml-technologies.md b/docs/standard/linq/linq-xml-vs-xml-technologies.md index a5af297e1aa3a..b29466e491811 100644 --- a/docs/standard/linq/linq-xml-vs-xml-technologies.md +++ b/docs/standard/linq/linq-xml-vs-xml-technologies.md @@ -29,7 +29,7 @@ XSLT can be a productive system that yields high-performance applications. For e However, XSLT doesn't take advantage of the C# and Visual Basic knowledge that many developers have. It requires developers to write code in a different and complex programming language. Using two non-integrated development systems such as C# (or Visual Basic) and XSLT results in software systems that are more difficult to develop and maintain. -After you have mastered LINQ to XML query expressions, LINQ to XML transformations are a powerful technology that's easy to use. Basically, you form your XML document by using functional construction, pulling in data from various sources, constructing objects dynamically, and assembling the whole into a new XML tree. The transformation can generate a completely new document. Constructing transformations in LINQ to XML is relatively easy and intuitive, and the resulting code is readable. This reduces development and maintenance costs. +After you've mastered LINQ to XML query expressions, LINQ to XML transformations are a powerful technology that's easy to use. Basically, you form your XML document by using functional construction, pulling in data from various sources, constructing objects dynamically, and assembling the whole into a new XML tree. The transformation can generate a completely new document. Constructing transformations in LINQ to XML is relatively easy and intuitive, and the resulting code is readable. This reduces development and maintenance costs. LINQ to XML isn't intended to replace XSLT. XSLT is still the tool of choice for complicated and document-centric XML transformations, especially if the structure of the document isn't well defined. diff --git a/docs/standard/linq/mixed-declarative-imperative-code-bugs.md b/docs/standard/linq/mixed-declarative-imperative-code-bugs.md new file mode 100644 index 0000000000000..01babd9e2502f --- /dev/null +++ b/docs/standard/linq/mixed-declarative-imperative-code-bugs.md @@ -0,0 +1,247 @@ +--- +title: Mixed declarative/imperative code bugs - LINQ to XML +description: Learn how to recognize and avoid problems that can occur when code iterates along an axis making changes. +ms.date: 07/20/2015 +dev_langs: + - "csharp" + - "vb" +ms.assetid: fada62d0-0680-4e73-945a-2b00d7a507af +--- + +# Mixed declarative/imperative code bugs (LINQ to XML) + +LINQ to XML contains various methods that allow you to modify an XML tree directly. You can add elements, delete elements, change the contents of an element, add attributes, and so on. This programming interface is described in [Modify XML trees](in-memory-xml-tree-modification-vs-functional-construction.md). If you're iterating through one of the axes, such as , and you're modifying the XML tree as you iterate through the axis, you can end up with some strange bugs. + +This problem is sometimes known as "The Halloween Problem". + +When you write some code using LINQ that iterates through a collection, you're writing code in a declarative style. It's more akin to describing *what* you want, rather that *how* you want to get it done. If you write code that 1) gets the first element, 2) tests it for some condition, 3) modifies it, and 4) puts it back into the list, then this would be imperative code. You're telling the computer *how* to do what you want done. + +Mixing these styles of code in the same operation is what leads to problems. Consider the following: + +Suppose you have a linked list with three items in it (a, b, and c): + +> a -> b -> c + +Now, suppose that you want to move through the linked list, adding three new items (a', b', and c'). You want the resulting linked list to look like this: + + > a -> a' -> b -> b' -> c -> c' + +So you write code that iterates through the list, and for every item, adds a new item right after it. What happens is that your code will first see the `a` element, and insert `a'` after it. Now, your code will move to the next node in the list, which is now `a'`, so it adds a new item between a' and b to the list! + +How would you solve this? Well, you might make a copy of the original linked list, and create a completely new list. Or if you're writing purely imperative code, you might find the first item, add the new item, and then advance twice in the linked list, advancing over the element that you just added. + +## Example: Adding while iterating + +For example, suppose you want to write code to create a duplicate of every element in a tree: + +```csharp +XElement root = new XElement("Root", + new XElement("A", "1"), + new XElement("B", "2"), + new XElement("C", "3") +); +foreach (XElement e in root.Elements()) + root.Add(new XElement(e.Name, (string)e)); +``` + +```vb +Dim root As XElement = _ + + 1 + 2 + 3 + +For Each e As XElement In root.Elements() + root.Add(New XElement(e.Name, e.Value)) +Next +``` + +This code goes into an infinite loop. The `foreach` statement iterates through the `Elements()` axis, adding new elements to the `doc` element. It ends up iterating also through the elements it just added. And because it allocates new objects with every iteration of the loop, it will eventually consume all available memory. + +You can fix this problem by pulling the collection into memory using the standard query operator, as follows: + +```csharp +XElement root = new XElement("Root", + new XElement("A", "1"), + new XElement("B", "2"), + new XElement("C", "3") +); +foreach (XElement e in root.Elements().ToList()) + root.Add(new XElement(e.Name, (string)e)); +Console.WriteLine(root); +``` + +```vb +Dim root As XElement = _ + + 1 + 2 + 3 + +For Each e As XElement In root.Elements().ToList() + root.Add(New XElement(e.Name, e.Value)) +Next +Console.WriteLine(root) +``` + +Now the code works. The resulting XML tree is the following: + +```xml + + 1 + 2 + 3 + 1 + 2 + 3 + +``` + +## Example: Deleting while iterating + +If you want to delete all nodes at a certain level, you might be tempted to write code like the following: + +```csharp +XElement root = new XElement("Root", + new XElement("A", "1"), + new XElement("B", "2"), + new XElement("C", "3") +); +foreach (XElement e in root.Elements()) + e.Remove(); +Console.WriteLine(root); +``` + +```vb +Dim root As XElement = _ + + 1 + 2 + 3 + +For Each e As XElement In root.Elements() + e.Remove() +Next +Console.WriteLine(root) +``` + +However, this doesn't do what you want. In this situation, after you've removed the first element, A, it's removed from the XML tree contained in root, and the code in the Elements method that does the iterating can't find the next element. + +This example produces the following output: + +```xml + + 2 + 3 + +``` + +The solution again is to call to materialize the collection, as follows: + +```csharp +XElement root = new XElement("Root", + new XElement("A", "1"), + new XElement("B", "2"), + new XElement("C", "3") +); +foreach (XElement e in root.Elements().ToList()) + e.Remove(); +Console.WriteLine(root); +``` + +```vb +Dim root As XElement = _ + + 1 + 2 + 3 + +For Each e As XElement In root.Elements().ToList() + e.Remove() +Next +Console.WriteLine(root) +``` + +This example produces the following output: + +```xml + +``` + +Alternatively, you can eliminate the iteration altogether by calling on the parent element: + +```csharp +XElement root = new XElement("Root", + new XElement("A", "1"), + new XElement("B", "2"), + new XElement("C", "3") +); +root.RemoveAll(); +Console.WriteLine(root); +``` + +```vb +Dim root As XElement = _ + + 1 + 2 + 3 + +root.RemoveAll() +Console.WriteLine(root) +``` + +## Example: Why LINQ can't automatically handle these issues + +One approach would be to always bring everything into memory instead of doing lazy evaluation. However, it would be very expensive in terms of performance and memory use. In fact, if LINQ, and LINQ to XML, were to take this approach, it would fail in real-world situations. + +Another possible approach would be to put some sort of transaction syntax into LINQ, and have the compiler attempt to analyze the code to determine if any particular collection needed to be materialized. However, attempting to determine all code that has side-effects is incredibly complex. Consider the following code: + +```csharp +var z = + from e in root.Elements() + where TestSomeCondition(e) + select DoMyProjection(e); +``` + +```vb +Dim z = _ + From e In root.Elements() _ + Where (TestSomeCondition(e)) _ + Select DoMyProjection(e) +``` + +Such analysis code would need to analyze the methods TestSomeCondition and DoMyProjection, and all methods that those methods called, to determine if any code had side-effects. But the analysis code could not just look for any code that had side-effects. It would need to select for just the code that had side-effects on the child elements of `root` in this situation. + +LINQ to XML doesn't attempt to do any such analysis. It's up to you to avoid these problems. + +## Example: Use declarative code to generate a new XML tree rather than modify the existing tree + +To avoid such problems, don't mix declarative and imperative code, even if you know exactly the semantics of your collections and the semantics of the methods that modify the XML tree. If you write code that avoids problems, your code will need to be maintained by other developers in the future, and they may not be as clear on the issues. If you mix declarative and imperative coding styles, your code will be more brittle. If you write code that materializes a collection so that these problems are avoided, note it with comments as appropriate in your code, so that maintenance programmers will understand the issue. + +If performance and other considerations allow, use only declarative code. Don't modify your existing XML tree. Instead, generate a new one as shown in the following example: + +```csharp +XElement root = new XElement("Root", + new XElement("A", "1"), + new XElement("B", "2"), + new XElement("C", "3") +); +XElement newRoot = new XElement("Root", + root.Elements(), + root.Elements() +); +Console.WriteLine(newRoot); +``` + +```vb +Dim root As XElement = _ + + 1 + 2 + 3 + +Dim newRoot As XElement = New XElement("Root", _ + root.Elements(), root.Elements()) +Console.WriteLine(newRoot) +``` diff --git a/docs/standard/linq/namespaces-overview.md b/docs/standard/linq/namespaces-overview.md index 6eca5730c4596..4d74f04957057 100644 --- a/docs/standard/linq/namespaces-overview.md +++ b/docs/standard/linq/namespaces-overview.md @@ -9,7 +9,7 @@ ms.assetid: 16283322-8238-4918-ab11-802ac6748eb7 This article introduces *XML names*, *XML namespaces*, *XML namespace prefixes*, and the and classes. -XML names are often a source of complexity in XML programming. An XML name consists of an XML namespace (also called an XML namespace URI) and a local name. An XML namespace is similar to a namespace in a .NET program. It enables you to uniquely qualify the names of elements and attributes to avoid name conflicts between various parts of an XML document. When you have declared an XML namespace, you can select a local name that only has to be unique within that namespace. +XML names are often a source of complexity in XML programming. An XML name consists of an XML namespace (also called an XML namespace URI) and a local name. An XML namespace is similar to a namespace in a .NET Framework-based program. It enables you to uniquely qualify the names of elements and attributes to avoid name conflicts between various parts of an XML document. When you've declared an XML namespace, you can select a local name that only has to be unique within that namespace. Another aspect of XML names is XML namespace prefixes, which cause most of the complexity of XML names. These prefixes enable you to create a shortcut for an XML namespace, which makes the XML document more concise and understandable. However, the meaning of an XML prefix depends on context, which adds complexity. For example, the XML prefix `aw` could be associated with one XML namespace in part of an XML tree, and with a different namespace in another part. diff --git a/docs/standard/linq/perform-streaming-transform-large-xml-documents.md b/docs/standard/linq/perform-streaming-transform-large-xml-documents.md new file mode 100644 index 0000000000000..4ae434ac564d1 --- /dev/null +++ b/docs/standard/linq/perform-streaming-transform-large-xml-documents.md @@ -0,0 +1,586 @@ +--- +title: How to perform streaming transform of large XML documents - LINQ to XML +description: Learn how to perform streaming transform of large XML documents to achieve a small memory footprint. +ms.date: 07/20/2015 +dev_langs: + - "csharp" + - "vb" +ms.assetid: 5f16d1f8-5370-4b55-b0c8-e497df163037 +--- + +# How to perform streaming transform of large XML documents (LINQ to XML) + +Sometimes you have to transform large XML files, and write your application so that the memory footprint of the application is predictable. If you try to populate an XML tree with a very large XML file, your memory usage will be proportional to the size of the file (that is, excessive). Therefore, you should use a streaming technique instead. + +Streaming techniques are best applied in situations where you need to process the source document only once, and you can process the elements in document order. Certain standard query operators, such as , iterate their source, collect all of the data, sort it, and then finally yield the first item in the sequence. Note that if you use a query operator that materializes its source before yielding the first item, you won't retain a small memory footprint for your application. + +Even if you use the technique described in [How to stream XML fragments with access to header information](stream-xml-fragments-access-header-information.md), if you try to assemble an XML tree that contains the transformed document, memory usage will be too great. + +There are two main approaches. One approach is to use the deferred processing characteristics of . Another approach is to create an , and use the capabilities of LINQ to XML to write elements to an . This article demonstrates both approaches. + +## Example: Use the deferred execution capabilities of `XStreamingElement` to stream the output + +The following example builds on the example in [How to stream XML fragments with access to header information](stream-xml-fragments-access-header-information.md). + +This example uses the deferred execution capabilities of to stream the output. This example can transform a very large document while maintaining a small memory footprint. + +Note that the custom axis (`StreamCustomerItem`) is specifically written so that it expects a document that has `Customer`, `Name`, and `Item` elements, and that those elements will be arranged as in the following Source.xml document. A more robust implementation, however, would be prepared to parse an invalid document. + +The following is the source document, Source.xml: + +```xml + + + + A. Datum Corporation + + 0001 + + + 0002 + + + 0003 + + + 0004 + + + + Fabrikam, Inc. + + 0005 + + + 0006 + + + 0007 + + + 0008 + + + + Southridge Video + + 0009 + + + 0010 + + + +``` + +```csharp +static IEnumerable StreamCustomerItem(string uri) +{ + using (XmlReader reader = XmlReader.Create(uri)) + { + XElement name = null; + XElement item = null; + + reader.MoveToContent(); + + // Parse the file, save header information when encountered, and yield the + // Item XElement objects as they're created. + + // loop through Customer elements + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element + && reader.Name == "Customer") + { + // move to Name element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element && + reader.Name == "Name") + { + name = XElement.ReadFrom(reader) as XElement; + break; + } + } + + // loop through Item elements + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.EndElement) + break; + if (reader.NodeType == XmlNodeType.Element + && reader.Name == "Item") + { + item = XElement.ReadFrom(reader) as XElement; + if (item != null) + { + XElement tempRoot = new XElement("Root", + new XElement(name) + ); + tempRoot.Add(item); + yield return item; + } + } + } + } + } + } +} + +static void Main(string[] args) +{ + XStreamingElement root = new XStreamingElement("Root", + from el in StreamCustomerItem("Source.xml") + select new XElement("Item", + new XElement("Customer", (string)el.Parent.Element("Name")), + new XElement(el.Element("Key")) + ) + ); + root.Save("Test.xml"); + Console.WriteLine(File.ReadAllText("Test.xml")); +} +``` + +```vb +Module Module1 + Sub Main() + Dim root = New XStreamingElement("Root", + From el In New StreamCustomerItem("Source.xml") + Select + <%= el.Parent..Value %> + <%= el. %> + + ) + root.Save("Test.xml") + Console.WriteLine(My.Computer.FileSystem.ReadAllText("Test.xml")) + End Sub +End Module + +Public Class StreamCustomerItem + Implements IEnumerable(Of XElement) + + Private _uri As String + + Public Sub New(ByVal uri As String) + _uri = uri + End Sub + + Public Function GetEnumerator() As IEnumerator(Of XElement) Implements IEnumerable(Of XElement).GetEnumerator + Return New StreamCustomerItemEnumerator(_uri) + End Function + + Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator + Return Me.GetEnumerator() + End Function +End Class + +Public Class StreamCustomerItemEnumerator + Implements IEnumerator(Of XElement) + + Private _current As XElement + Private _customerName As String + Private _reader As Xml.XmlReader + Private _uri As String + + Public Sub New(ByVal uri As String) + _uri = uri + _reader = Xml.XmlReader.Create(_uri) + _reader.MoveToContent() + End Sub + + Public ReadOnly Property Current As XElement Implements IEnumerator(Of XElement).Current + Get + Return _current + End Get + End Property + + Public ReadOnly Property Current1 As Object Implements IEnumerator.Current + Get + Return Me.Current + End Get + End Property + + Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext + Dim item As XElement + Dim name As XElement + + ' Parse the file, save header information when encountered, and return the + ' current Item XElement. + + ' loop through Customer elements + While _reader.Read() + If _reader.NodeType = Xml.XmlNodeType.Element Then + Select Case _reader.Name + Case "Customer" + ' move to Name element + While _reader.Read() + + If _reader.NodeType = Xml.XmlNodeType.Element AndAlso + _reader.Name = "Name" Then + + name = TryCast(XElement.ReadFrom(_reader), XElement) + _customerName = If(name IsNot Nothing, name.Value, "") + Exit While + End If + + End While + Case "Item" + item = TryCast(XElement.ReadFrom(_reader), XElement) + Dim tempRoot = + <%= _customerName %> + <%= item %> + + _current = item + Return True + End Select + End If + End While + + Return False + End Function + + Public Sub Reset() Implements IEnumerator.Reset + _reader = Xml.XmlReader.Create(_uri) + _reader.MoveToContent() + End Sub + +#Region "IDisposable Support" + Private disposedValue As Boolean ' To detect redundant calls + + ' IDisposable + Protected Overridable Sub Dispose(ByVal disposing As Boolean) + If Not Me.disposedValue Then + If disposing Then + _reader.Close() + End If + End If + Me.disposedValue = True + End Sub + + Public Sub Dispose() Implements IDisposable.Dispose + Dispose(True) + GC.SuppressFinalize(Me) + End Sub +#End Region + +End Class +``` + +This example produces the following output: + +```xml + + + + A. Datum Corporation + 0001 + + + A. Datum Corporation + 0002 + + + A. Datum Corporation + 0003 + + + A. Datum Corporation + 0004 + + + Fabrikam, Inc. + 0005 + + + Fabrikam, Inc. + 0006 + + + Fabrikam, Inc. + 0007 + + + Fabrikam, Inc. + 0008 + + + Southridge Video + 0009 + + + Southridge Video + 0010 + + +``` + +## Example: Use LINQ to XML to write elements to an XmlWriter + +The following example also builds on the example in [How to stream XML fragments with access to header information](stream-xml-fragments-access-header-information.md). + +This example uses the capability of LINQ to XML to write elements to an . This example can transform a very large document while maintaining a small memory footprint. + +Note that the custom axis (`StreamCustomerItem`) is specifically written so that it expects a document that has `Customer`, `Name`, and `Item` elements, and that those elements will be arranged as in the following Source.xml document. A more robust implementation, however, would either validate the source document with an XSD, or would be prepared to parse an invalid document. + +This example uses the same source document, Source.xml, as the previous example. It also produces exactly the same output. + +Using for streaming the output XML is preferred to writing to an . + +```csharp +static IEnumerable StreamCustomerItem(string uri) +{ + using (XmlReader reader = XmlReader.Create(uri)) + { + XElement name = null; + XElement item = null; + + reader.MoveToContent(); + + // Parse the file, save header information when encountered, and yield the + // Item XElement objects as they're created. + + // loop through Customer elements + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element + && reader.Name == "Customer") + { + // move to Name element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element && + reader.Name == "Name") + { + name = XElement.ReadFrom(reader) as XElement; + break; + } + } + + // loop through Item elements + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.EndElement) + break; + if (reader.NodeType == XmlNodeType.Element + && reader.Name == "Item") + { + item = XElement.ReadFrom(reader) as XElement; + if (item != null) { + XElement tempRoot = new XElement("Root", + new XElement(name) + ); + tempRoot.Add(item); + yield return item; + } + } + } + } + } + } +} + +static void Main(string[] args) +{ + IEnumerable srcTree = + from el in StreamCustomerItem("Source.xml") + select new XElement("Item", + new XElement("Customer", (string)el.Parent.Element("Name")), + new XElement(el.Element("Key")) + ); + XmlWriterSettings xws = new XmlWriterSettings(); + xws.OmitXmlDeclaration = true; + xws.Indent = true; + using (XmlWriter xw = XmlWriter.Create("Output.xml", xws)) { + xw.WriteStartElement("Root"); + foreach (XElement el in srcTree) + el.WriteTo(xw); + xw.WriteEndElement(); + } + + string str = File.ReadAllText("Output.xml"); + Console.WriteLine(str); +} +``` + +```vb +Module Module1 + Sub Main() + Dim srcTree = + From el In New StreamCustomerItem("Source.xml") + Select + <%= el.Parent..Value %> + <%= el. %> + + + Dim xws = New Xml.XmlWriterSettings() + xws.OmitXmlDeclaration = True + xws.Indent = True + Using xw = Xml.XmlWriter.Create("Output.xml", xws) + xw.WriteStartElement("Root") + For Each el In srcTree + el.WriteTo(xw) + Next + xw.WriteEndElement() + End Using + + Dim s = My.Computer.FileSystem.ReadAllText("Output.xml") + Console.WriteLine(s) + End Sub +End Module + +Public Class StreamCustomerItem + Implements IEnumerable(Of XElement) + + Private _uri As String + + Public Sub New(ByVal uri As String) + _uri = uri + End Sub + + Public Function GetEnumerator() As IEnumerator(Of XElement) Implements IEnumerable(Of XElement).GetEnumerator + Return New StreamCustomerItemEnumerator(_uri) + End Function + + Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator + Return Me.GetEnumerator() + End Function +End Class + +Public Class StreamCustomerItemEnumerator + Implements IEnumerator(Of XElement) + + Private _current As XElement + Private _customerName As String + Private _reader As Xml.XmlReader + Private _uri As String + + Public Sub New(ByVal uri As String) + _uri = uri + _reader = Xml.XmlReader.Create(_uri) + _reader.MoveToContent() + End Sub + + Public ReadOnly Property Current As XElement Implements IEnumerator(Of XElement).Current + Get + Return _current + End Get + End Property + + Public ReadOnly Property Current1 As Object Implements IEnumerator.Current + Get + Return Me.Current + End Get + End Property + + Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext + Dim item As XElement + Dim name As XElement + + ' Parse the file, save header information when encountered, and return the + ' current Item XElement. + + ' loop through Customer elements + While _reader.Read() + If _reader.NodeType = Xml.XmlNodeType.Element Then + Select Case _reader.Name + Case "Customer" + ' move to Name element + While _reader.Read() + + If _reader.NodeType = Xml.XmlNodeType.Element AndAlso + _reader.Name = "Name" Then + + name = TryCast(XElement.ReadFrom(_reader), XElement) + _customerName = If(name IsNot Nothing, name.Value, "") + Exit While + End If + + End While + Case "Item" + item = TryCast(XElement.ReadFrom(_reader), XElement) + Dim tempRoot = + <%= _customerName %> + <%= item %> + + _current = item + Return True + End Select + End If + End While + + Return False + End Function + + Public Sub Reset() Implements IEnumerator.Reset + _reader = Xml.XmlReader.Create(_uri) + _reader.MoveToContent() + End Sub + +#Region "IDisposable Support" + Private disposedValue As Boolean ' To detect redundant calls + + ' IDisposable + Protected Overridable Sub Dispose(ByVal disposing As Boolean) + If Not Me.disposedValue Then + If disposing Then + _reader.Close() + End If + End If + Me.disposedValue = True + End Sub + + Public Sub Dispose() Implements IDisposable.Dispose + Dispose(True) + GC.SuppressFinalize(Me) + End Sub +#End Region + +End Class +``` + +This example produces the following output: + +```xml + + + A. Datum Corporation + 0001 + + + A. Datum Corporation + 0002 + + + A. Datum Corporation + 0003 + + + A. Datum Corporation + 0004 + + + Fabrikam, Inc. + 0005 + + + Fabrikam, Inc. + 0006 + + + Fabrikam, Inc. + 0007 + + + Fabrikam, Inc. + 0008 + + + Southridge Video + 0009 + + + Southridge Video + 0010 + + +``` diff --git a/docs/standard/linq/reference.md b/docs/standard/linq/reference.md new file mode 100644 index 0000000000000..620459b11c08a --- /dev/null +++ b/docs/standard/linq/reference.md @@ -0,0 +1,20 @@ +--- +title: Reference - LINQ to XML +description: Find LINQ to XML reference articles. +ms.date: 07/20/2015 +ms.assetid: 815b45e2-3527-4dee-9986-b1277a693cde +--- + +# Reference (LINQ to XML) + +This article contains links to the LINQ to XML reference articles. + +For reference documentation for the LINQ to XML classes, see . + +For reference documentation for the extension methods that help you validate XML trees against an XSD file, see . + +For reference documentation for the extension methods that enable you to evaluate XPath queries on an XML tree, see . + +## See also + +- [LINQ to XML overview](linq-xml-overview.md) diff --git a/docs/standard/linq/serialize-datacontractserializer.md b/docs/standard/linq/serialize-datacontractserializer.md new file mode 100644 index 0000000000000..cf7969a71baf6 --- /dev/null +++ b/docs/standard/linq/serialize-datacontractserializer.md @@ -0,0 +1,150 @@ +--- +title: How to serialize using DataContractSerializer - LINQ to XML +description: Learn how to serialize and deserialize using DataContractSerializer. +ms.date: 07/20/2015 +dev_langs: + - "csharp" + - "vb" +ms.assetid: 3320ecbf-cdbe-480e-979c-2c14bbef9988 +--- + +# How to serialize using DataContractSerializer (LINQ to XML) + +This article shows an example that serializes and deserializes using . + +## Example: Create objects that contain `XElement` objects, then serialize and deserialize them + +The following example creates a number of objects that contain objects. It then serializes them to text files, and then deserializes them from the text files. + +```csharp +using System; +using System.Xml; +using System.Xml.Linq; +using System.IO; +using System.Runtime.Serialization; + +public class XLinqTest +{ + public static void Main() + { + Test(CreateXElement()); + Test(new XElementContainer()); + Test(new XElementNullContainer()); + } + + public static void Test(T obj) + { + DataContractSerializer s = new DataContractSerializer(typeof(T)); + using (FileStream fs = File.Open("test" + typeof(T).Name + ".xml", FileMode.Create)) + { + Console.WriteLine("Testing for type: {0}", typeof(T)); + s.WriteObject(fs, obj); + } + using (FileStream fs = File.Open("test" + typeof(T).Name + ".xml", FileMode.Open)) + { + object s2 = s.ReadObject(fs); + if (s2 == null) + Console.WriteLine(" Deserialized object is null (Nothing in VB)"); + else + Console.WriteLine(" Deserialized type: {0}", s2.GetType()); + } + } + + public static XElement CreateXElement() + { + return new XElement(XName.Get("NameInNamespace", "http://www.adventure-works.org")); + } +} + +[DataContract] +public class XElementContainer +{ + [DataMember] + public XElement member; + + public XElementContainer() + { + member = XLinqTest.CreateXElement(); + } +} + +[DataContract] +public class XElementNullContainer +{ + [DataMember] + public XElement member; + + public XElementNullContainer() + { + member = null; + } +} +``` + +```vb +Imports System +Imports System.Xml +Imports System.Xml.Linq +Imports System.IO +Imports System.Runtime.Serialization + +Public Class XLinqTest + Shared Sub Main() + Test(Of XElement)(CreateXElement()) + Test(Of XElementContainer)(New XElementContainer()) + Test(Of XElementNullContainer)(New XElementNullContainer()) + End Sub + + Public Shared Sub Test(Of T)(ByRef obj) + Dim s As DataContractSerializer = New DataContractSerializer(GetType(T)) + Using fs As FileStream = File.Open("test" & GetType(T).Name & ".xml", FileMode.Create) + Console.WriteLine("Testing for type: {0}", GetType(T)) + s.WriteObject(fs, obj) + End Using + + Using fs As FileStream = File.Open("test" & GetType(T).Name & ".xml", FileMode.Open) + Dim s2 As Object = s.ReadObject(fs) + If s2 Is Nothing Then + Console.WriteLine(" Deserialized object is null (Nothing in VB)") + Else + Console.WriteLine(" Deserialized type: {0}", s2.GetType()) + End If + End Using + End Sub + + Public Shared Function CreateXElement() As XElement + Return New XElement(XName.Get("NameInNamespace", "http://www.adventure-works.org")) + End Function +End Class + + _ +Public Class XElementContainer + _ + Public member As XElement + + Public Sub XElementContainer() + member = XLinqTest.CreateXElement() + End Sub +End Class + + _ +Public Class XElementNullContainer + _ + Public member As XElement + + Public Sub XElementNullContainer() + member = Nothing + End Sub +End Class +``` + + This example produces the following output: + +```output +Testing for type: System.Xml.Linq.XElement + Deserialized type: System.Xml.Linq.XElement +Testing for type: XElementContainer + Deserialized type: XElementContainer +Testing for type: XElementNullContainer + Deserialized type: XElementNullContainer +``` diff --git a/docs/standard/linq/serialize-xmlserializer.md b/docs/standard/linq/serialize-xmlserializer.md new file mode 100644 index 0000000000000..2dcead91a8845 --- /dev/null +++ b/docs/standard/linq/serialize-xmlserializer.md @@ -0,0 +1,145 @@ +--- +title: How to serialize using XmlSerializer - LINQ to XML +description: Learn how to serialize and deserialize using XmlSerializer. +ms.date: 07/20/2015 +dev_langs: + - "csharp" + - "vb" +ms.assetid: 2e0a0bbc-c548-4fe2-8741-be5a9ccd0cbb +--- + +# How to serialize using XmlSerializer (LINQ to XML) + +This article shows an example that serializes and deserializes using . + +## Example: Create objects that contain `XElement` objects, then serialize and deserialize them + +The following example creates a number of objects that contain objects. It then serializes them to a memory stream, and then deserializes them from the memory stream. + +```csharp +using System; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Serialization; +using System.Xml.Linq; + +public class XElementContainer +{ + public XElement member; + + public XElementContainer() + { + member = XLinqTest.CreateXElement(); + } + + public override string ToString() + { + return member.ToString(); + } +} + +public class XElementNullContainer +{ + public XElement member; + + public XElementNullContainer() + { + } +} + +class XLinqTest +{ + static void Main(string[] args) + { + Test(new XElementNullContainer()); + Test(CreateXElement()); + Test(new XElementContainer()); + } + + public static XElement CreateXElement() + { + XNamespace ns = "http://www.adventure-works.com"; + return new XElement(ns + "aw"); + } + + static void Test(T obj) + { + using (MemoryStream stream = new MemoryStream()) + { + XmlSerializer s = new XmlSerializer(typeof(T)); + Console.WriteLine("Testing for type: {0}", typeof(T)); + s.Serialize(XmlWriter.Create(stream), obj); + stream.Flush(); + stream.Seek(0, SeekOrigin.Begin); + object o = s.Deserialize(XmlReader.Create(stream)); + Console.WriteLine(" Deserialized type: {0}", o.GetType()); + } + } +} +``` + +```vb +Imports System +Imports System.Xml +Imports System.Xml.Linq +Imports System.IO +Imports System.Runtime.Serialization +Imports System.Xml.Serialization + +Public Class XElementContainer + Public member As XElement + + Public Sub XElementContainer() + member = XLinqTest.CreateXElement() + End Sub + + Overrides Function ToString() As String + Return member.ToString() + End Function +End Class + +Public Class XElementNullContainer + Public member As XElement + + Public Sub XElementNullContainer() + member = Nothing + End Sub +End Class + +Public Class XLinqTest + Shared Sub Main() + Test(Of XElementNullContainer)(New XElementNullContainer()) + Test(Of XElement)(CreateXElement()) + Test(Of XElementContainer)(New XElementContainer()) + End Sub + + Public Shared Function CreateXElement() As XElement + Dim ns As XNamespace = "http://www.adventure-works.com" + Return New XElement(ns + "aw") + End Function + + Public Shared Sub Test(Of T)(ByRef obj) + Using stream As New MemoryStream() + Dim s As XmlSerializer = New XmlSerializer(GetType(T)) + Console.WriteLine("Testing for type: {0}", GetType(T)) + s.Serialize(XmlWriter.Create(stream), obj) + stream.Flush() + stream.Seek(0, SeekOrigin.Begin) + Dim o As Object = s.Deserialize(XmlReader.Create(stream)) + Console.WriteLine(" Deserialized type: {0}", o.GetType()) + End Using + End Sub +End Class +``` + +This example produces the following output: + +```output +Testing for type: XElementNullContainer + Deserialized type: XElementNullContainer +Testing for type: System.Xml.Linq.XElement + Deserialized type: System.Xml.Linq.XElement +Testing for type: XElementContainer + Deserialized type: XElementContainer +``` diff --git a/docs/standard/linq/stream-xml-fragments-access-header-information.md b/docs/standard/linq/stream-xml-fragments-access-header-information.md new file mode 100644 index 0000000000000..ffd91ea14ecaa --- /dev/null +++ b/docs/standard/linq/stream-xml-fragments-access-header-information.md @@ -0,0 +1,299 @@ +--- +title: How to stream XML fragments with access to header information - LINQ to XML +description: Learn how to implement and use a custom axis method that streams XML fragments from the file specified by a URI. +ms.date: 07/20/2015 +dev_langs: + - "csharp" + - "vb" +ms.assetid: 7f242770-b0c7-418d-894b-643215e1f8aa +--- + +# How to stream XML fragments with access to header information (LINQ to XML) + +Sometimes you have to read arbitrarily large XML files, and write your application so that the memory footprint of the application is predictable. If you attempt to populate an XML tree with a large XML file, your memory usage will be proportional to the size of the file—that is, excessive. Therefore, you should use a streaming technique instead. + +One option is to write your application using . However, you might want to use LINQ to query the XML tree. If so, you can write your own custom axis method. For more information, see [How to write a LINQ to XML axis method](write-linq-xml-axis-method.md). + +To write your own axis method, you write a small method that uses the to read nodes until it reaches one of the nodes in which you're interested. The method then calls , which reads from the and instantiates an XML fragment. It then yields each fragment through `yield return` to the method that's enumerating your custom axis method. You can then write LINQ queries on your custom axis method. + +Streaming techniques are best applied in situations where you need to process the source document only once, and you can process the elements in document order. Certain standard query operators, such as , iterate their source, collect all of the data, sort it, and then finally yield the first item in the sequence. If you use a query operator that materializes its source before yielding the first item, you won't retain a small memory footprint. + +## Example: Implement and use a custom axis method that streams XML fragments from the file specified by a URI + +Sometimes the problem gets just a little more interesting. In the following XML document, the consumer of your custom axis method also has to know the name of the customer that each item belongs to. + +```xml + + + + A. Datum Corporation + + 0001 + + + 0002 + + + 0003 + + + 0004 + + + + Fabrikam, Inc. + + 0005 + + + 0006 + + + 0007 + + + 0008 + + + + Southridge Video + + 0009 + + + 0010 + + + +``` + +The approach that this example takes is to also watch for this header information, save the header information, and then build a small XML tree that contains both the header information and the detail that you're enumerating. The axis method then yields this new, small XML tree. The query then has access to the header information as well as the detail information. + +This approach has a small memory footprint. As each detail XML fragment is yielded, no references are kept to the previous fragment, and it's available for garbage collection. This technique creates many short lived objects on the heap. + +The following example shows how to implement and use a custom axis method that streams XML fragments from the file specified by the URI. This custom axis is written such that it expects a document that has `Customer`, `Name`, and `Item` elements, and that those elements will be arranged as in the above `Source.xml` document. It's a simplistic implementation. A more robust implementation would be prepared to parse an invalid document. + +```csharp +static IEnumerable StreamCustomerItem(string uri) +{ + using (XmlReader reader = XmlReader.Create(uri)) + { + XElement name = null; + XElement item = null; + + reader.MoveToContent(); + + // Parse the file, save header information when encountered, and yield the + // Item XElement objects as they're created. + + // loop through Customer elements + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element + && reader.Name == "Customer") + { + // move to Name element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element && + reader.Name == "Name") + { + name = XElement.ReadFrom(reader) as XElement; + break; + } + } + + // loop through Item elements + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.EndElement) + break; + if (reader.NodeType == XmlNodeType.Element + && reader.Name == "Item") + { + item = XElement.ReadFrom(reader) as XElement; + if (item != null) { + XElement tempRoot = new XElement("Root", + new XElement(name) + ); + tempRoot.Add(item); + yield return item; + } + } + } + } + } + } +} + +static void Main(string[] args) +{ + XElement xmlTree = new XElement("Root", + from el in StreamCustomerItem("Source.xml") + where (int)el.Element("Key") >= 3 && (int)el.Element("Key") <= 7 + select new XElement("Item", + new XElement("Customer", (string)el.Parent.Element("Name")), + new XElement(el.Element("Key")) + ) + ); + Console.WriteLine(xmlTree); +} +``` + +```vb +Module Module1 + + Sub Main() + Dim xmlTree = + <%= + From el In New StreamCustomerItem("Source.xml") + Let itemKey = CInt(el..Value) + Where itemKey >= 3 AndAlso itemKey <= 7 + Select + <%= el.Parent..Value %> + <%= el. %> + + %> + + + Console.WriteLine(xmlTree) + End Sub + +End Module + +Public Class StreamCustomerItem + Implements IEnumerable(Of XElement) + + Private _uri As String + + Public Sub New(ByVal uri As String) + _uri = uri + End Sub + + Public Function GetEnumerator() As IEnumerator(Of XElement) Implements IEnumerable(Of XElement).GetEnumerator + Return New StreamCustomerItemEnumerator(_uri) + End Function + + Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator + Return Me.GetEnumerator() + End Function +End Class + +Public Class StreamCustomerItemEnumerator + Implements IEnumerator(Of XElement) + + Private _current As XElement + Private _customerName As String + Private _reader As Xml.XmlReader + Private _uri As String + + Public Sub New(ByVal uri As String) + _uri = uri + _reader = Xml.XmlReader.Create(_uri) + _reader.MoveToContent() + End Sub + + Public ReadOnly Property Current As XElement Implements IEnumerator(Of XElement).Current + Get + Return _current + End Get + End Property + + Public ReadOnly Property Current1 As Object Implements IEnumerator.Current + Get + Return Me.Current + End Get + End Property + + Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext + Dim item As XElement + Dim name As XElement + + ' Parse the file, save header information when encountered, and return the + ' current Item XElement. + + ' loop through Customer elements + While _reader.Read() + If _reader.NodeType = Xml.XmlNodeType.Element Then + Select Case _reader.Name + Case "Customer" + ' move to Name element + While _reader.Read() + + If _reader.NodeType = Xml.XmlNodeType.Element AndAlso + _reader.Name = "Name" Then + + name = TryCast(XElement.ReadFrom(_reader), XElement) + _customerName = If(name IsNot Nothing, name.Value, "") + Exit While + End If + + End While + Case "Item" + item = TryCast(XElement.ReadFrom(_reader), XElement) + Dim tempRoot = + <%= _customerName %> + <%= item %> + + _current = item + Return True + End Select + End If + End While + + Return False + End Function + + Public Sub Reset() Implements IEnumerator.Reset + _reader = Xml.XmlReader.Create(_uri) + _reader.MoveToContent() + End Sub + +#Region "IDisposable Support" + Private disposedValue As Boolean ' To detect redundant calls + + ' IDisposable + Protected Overridable Sub Dispose(ByVal disposing As Boolean) + If Not Me.disposedValue Then + If disposing Then + _reader.Close() + End If + End If + Me.disposedValue = True + End Sub + + Public Sub Dispose() Implements IDisposable.Dispose + Dispose(True) + GC.SuppressFinalize(Me) + End Sub +#End Region + +End Class +``` + + This code produces the following output: + +```xml + + + A. Datum Corporation + 0003 + + + A. Datum Corporation + 0004 + + + Fabrikam, Inc. + 0005 + + + Fabrikam, Inc. + 0006 + + + Fabrikam, Inc. + 0007 + + +``` diff --git a/docs/standard/linq/use-annotations-transform-linq-xml-trees-xslt-style.md b/docs/standard/linq/use-annotations-transform-linq-xml-trees-xslt-style.md new file mode 100644 index 0000000000000..bca89483d636d --- /dev/null +++ b/docs/standard/linq/use-annotations-transform-linq-xml-trees-xslt-style.md @@ -0,0 +1,645 @@ +--- +title: How to use annotations to transform LINQ to XML trees in an XSLT style - LINQ to XML +description: +ms.date: 07/20/2015 +dev_langs: + - "csharp" + - "vb" +ms.assetid: 12a95902-a6b7-4a1e-ad52-04a518db226f +--- +# How to use annotations to transform LINQ to XML trees in an XSLT style (LINQ to XML) + +Annotations can be used to facilitate transforms of an XML tree. + +Some XML documents are "document-centric with mixed content." With such documents, you don't necessarily know the shape of child nodes of an element. For instance, a node that contains text may look like this: + +```xml +A phrase with bold and italic text. +``` + +For any given text node, there may be any number of child `` and `` elements. This approach extends to a number of other situations, such as pages that can contain a variety of child elements, which could be regular paragraphs, bulleted paragraphs, and bitmaps. Cells in a table may contain text, drop down lists, or bitmaps. One of the primary characteristics of document-centric XML is that you don't know which child element any particular element will have. + +If you want to transform elements in a tree where you don't necessarily know much about the children of the elements that you want to transform, then this approach that uses annotations is an effective one. + +The summary of the approach is: + +- First, annotate elements in the tree with a replacement element. +- Second, iterate through the entire tree, creating a new tree where you replace each element with its annotation. The examples in this article implement the iteration and creation of the new tree in a function named `XForm`. + +In detail, the approach consists of: + +- Execute one or more LINQ to XML queries that return the set of elements that you want to transform from one shape to another. For each element in the query, add a new object as an annotation to the element. This new element will replace the annotated element in the new, transformed tree. This is simple code to write, as demonstrated by the example. +- The new element that's added as an annotation can contain new child nodes; it can form a subtree with any desired shape. +- There is a special rule: If a child node of the new element is in a different namespace, a namespace that's made up for this purpose (in this example, the namespace is `http://www.microsoft.com/LinqToXmlTransform/2007`), then that child element isn't copied to the new tree. Instead, if the namespace is the above-mentioned special namespace, and the local name of the element is `ApplyTransforms`, then the child nodes of the element in the source tree are iterated, and copied to the new tree (with the exception that annotated child elements are themselves transformed according to these rules). +- This is somewhat analogous to the specification of transforms in XSL. The query that selects a set of nodes is analogous to the XPath expression for a template. The code to create the new that's saved as an annotation is analogous to the sequence constructor in XSL, and the `ApplyTransforms` element is analogous in function to the `xsl:apply-templates` element in XSL. +- One advantage to taking this approach is that, as you formulate queries, you're always writing queries on the unmodified source tree. You need not worry about how modifications to the tree affect the queries that you're writing. + +## Example: Rename all paragraph nodes + +This example renames all `Paragraph` nodes to `para`. + +```csharp +XNamespace xf = "http://www.microsoft.com/LinqToXmlTransform/2007"; +XName at = xf + "ApplyTransforms"; + +XElement root = XElement.Parse(@" + + This is a sentence with bold and italic text. + More text. +"); + +// replace Paragraph with para +foreach (var el in root.Descendants("Paragraph")) + el.AddAnnotation( + new XElement("para", + // same idea as xsl:apply-templates + new XElement(xf + "ApplyTransforms") + ) + ); + +// The XForm method, shown later in this article, accomplishes the transform +XElement newRoot = XForm(root); + +Console.WriteLine(newRoot); +``` + +```vb +Imports + +Module Module1 + Dim at As XName = GetXmlNamespace(xf) + "ApplyTransforms" + + Sub Main() + Dim root As XElement = _ + + This is a sentence with bold and italic text. + More text. + + + ' Replace Paragraph with p. + For Each el In root... + ' same idea as xsl:apply-templates + el.AddAnnotation( _ + + <<%= at %>> + ) + Next + + ' The XForm function, shown later in this article, accomplishes the transform + Dim newRoot As XElement = XForm(root) + Console.WriteLine(newRoot) + End Sub +End Module +``` + +This example produces the following output: + +```xml + + This is a sentence with bold and italic text. + More text. + +``` + +## Example: Calculate averages and sums and add them as new elements to the tree + +The following example calculates the average and sum of the `Data` elements and adds them as new elements to the tree. + +```csharp +XNamespace xf = "http://www.microsoft.com/LinqToXmlTransform/2007"; +XName at = xf + "ApplyTransforms"; + +XElement data = new XElement("Root", + new XElement("Data", 20), + new XElement("Data", 10), + new XElement("Data", 3) +); + +// while adding annotations, you can query the source tree all you want, +// as the tree isn't mutated while annotating. +var avg = data.Elements("Data").Select(z => (Decimal)z).Average(); +data.AddAnnotation( + new XElement("Root", + new XElement(xf + "ApplyTransforms"), + new XElement("Average", $"{avg:F4}"), + new XElement("Sum", + data + .Elements("Data") + .Select(z => (int)z) + .Sum() + ) + ) +); + +Console.WriteLine("Before Transform"); +Console.WriteLine("----------------"); +Console.WriteLine(data); +Console.WriteLine(); +Console.WriteLine(); + +// The XForm method, shown later in this article, accomplishes the transform +XElement newData = XForm(data); + +Console.WriteLine("After Transform"); +Console.WriteLine("----------------"); +Console.WriteLine(newData); +``` + +```vb +Imports + +Module Module1 + Dim at As XName = GetXmlNamespace(xf) + "ApplyTransforms" + + Sub Main() + Dim data As XElement = _ + + 20 + 10 + 3 + + + ' While adding annotations, you can query the source tree all you want, + ' as the tree isn't mutated while annotating. + data.AddAnnotation( _ + + <<%= at %>/> + + <%= _ + String.Format("{0:F4}", _ + data.Elements("Data") _ + .Select(Function(z) CDec(z)).Average()) _ + %> + + + <%= _ + data.Elements("Data").Select(Function(z) CInt(z)).Sum() _ + %> + + _ + ) + + Console.WriteLine("Before Transform") + Console.WriteLine("----------------") + Console.WriteLine(data) + Console.WriteLine(vbNewLine) + + ' The XForm function, shown later in this article, accomplishes the transform + Dim newData As XElement = XForm(data) + + Console.WriteLine("After Transform") + Console.WriteLine("----------------") + Console.WriteLine(newData) + End Sub +End Module +``` + +This example produces the following output: + +```output +Before Transform +---------------- + + 20 + 10 + 3 + + +After Transform +---------------- + + 20 + 10 + 3 + 11.0000 + 33 + +``` + +## Example: Create a new transformed tree from the original annotated tree + +A small function, `XForm`, creates a new transformed tree from the original, annotated tree. The following is pseudocode for this function: + +> The function takes an XElement as an argument and returns an XElement. +> +> If an element has an XElement annotation, the returned XElement has these characteristics: +> +> - The name of the new XElement is the annotation element's name. +> - All attributes are copied from the annotation to the new node. +> - All child nodes are copied from the annotation, with the exception that the special node xf:ApplyTransforms is recognized, and the source element's child nodes are iterated. If the source child node isn't an XElement, it's copied to the new tree. If the source child is an XElement, then it's transformed by calling this function recursively. +> +> Otherwise, the returned XElement has these characteristics: +> +> - The name of the new XElement is the source element's name. +> - All attributes are copied from the source element to the destination's element. +> - All child nodes are copied from the source element. +> - If the source child node isn't an XElement, it's copied to the new tree. If the source child is an XElement, then it's transformed by calling this function recursively. + +The following is code for this function: + +```csharp +// Build a transformed XML tree per the annotations +static XElement XForm(XElement source) +{ + XNamespace xf = "http://www.microsoft.com/LinqToXmlTransform/2007"; + XName at = xf + "ApplyTransforms"; + + if (source.Annotation() != null) + { + XElement anno = source.Annotation(); + return new XElement(anno.Name, + anno.Attributes(), + anno + .Nodes() + .Select( + (XNode n) => + { + XElement annoEl = n as XElement; + if (annoEl != null) + { + if (annoEl.Name == at) + return (object)( + source.Nodes() + .Select( + (XNode n2) => + { + XElement e2 = n2 as XElement; + if (e2 == null) + return n2; + else + return XForm(e2); + } + ) + ); + else + return n; + } + else + return n; + } + ) + ); + } + else + { + return new XElement(source.Name, + source.Attributes(), + source + .Nodes() + .Select(n => + { + XElement el = n as XElement; + if (el == null) + return n; + else + return XForm(el); + } + ) + ); + } +} +``` + +```vb +' Build a transformed XML tree per the annotations. +Function XForm(ByVal source As XElement) As XElement + If source.Annotation(Of XElement)() IsNot Nothing Then + Dim anno As XElement = source.Annotation(Of XElement)() + Return _ + <<%= anno.Name.ToString() %>> + <%= anno.Attributes() %> + <%= anno.Nodes().Select(Function(n As XNode) _ + GetSubNodes(n, source)) %> + + Else + Return _ + <<%= source.Name %>> + <%= source.Attributes() %> + <%= source.Nodes().Select(Function(n) GetExpandedNodes(n)) %> + + End If +End Function + +Private Function GetSubNodes(ByVal n As XNode, ByVal s As XElement) As Object + Dim annoEl As XElement = TryCast(n, XElement) + If annoEl IsNot Nothing Then + If annoEl.Name = at Then + Return s.Nodes().Select(Function(n2 As XNode) GetExpandedNodes(n2)) + End If + End If + Return n +End Function + +Private Function GetExpandedNodes(ByVal n2 As XNode) As XNode + Dim e2 As XElement = TryCast(n2, XElement) + If e2 Is Nothing Then + Return n2 + Else + Return XForm(e2) + End If +End Function +``` + +## Example: Show `XForm` in typical uses of this type of transform + +The following example includes the `XForm` function and a few of the typical uses of this type of transform: + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; +using System.Xml.Linq; + +class Program +{ + static XNamespace xf = "http://www.microsoft.com/LinqToXmlTransform/2007"; + static XName at = xf + "ApplyTransforms"; + + // Build a transformed XML tree per the annotations + static XElement XForm(XElement source) + { + if (source.Annotation() != null) + { + XElement anno = source.Annotation(); + return new XElement(anno.Name, + anno.Attributes(), + anno + .Nodes() + .Select( + (XNode n) => + { + XElement annoEl = n as XElement; + if (annoEl != null) + { + if (annoEl.Name == at) + return (object)( + source.Nodes() + .Select( + (XNode n2) => + { + XElement e2 = n2 as XElement; + if (e2 == null) + return n2; + else + return XForm(e2); + } + ) + ); + else + return n; + } + else + return n; + } + ) + ); + } + else + { + return new XElement(source.Name, + source.Attributes(), + source + .Nodes() + .Select(n => + { + XElement el = n as XElement; + if (el == null) + return n; + else + return XForm(el); + } + ) + ); + } + } + + static void Main(string[] args) + { + XElement root = new XElement("Root", + new XComment("A comment"), + new XAttribute("Att1", 123), + new XElement("Child", 1), + new XElement("Child", 2), + new XElement("Other", + new XElement("GC", 3), + new XElement("GC", 4) + ), + XElement.Parse( + "This is an element that " + + "has some mixed content"), + new XElement("AnUnchangedElement", 42) + ); + + // each of the following serves the same semantic purpose as + // XSLT templates and sequence constructors + + // replace Child with NewChild + foreach (var el in root.Elements("Child")) + el.AddAnnotation(new XElement("NewChild", (string)el)); + + // replace first GC with GrandChild, add an attribute + foreach (var el in root.Descendants("GC").Take(1)) + el.AddAnnotation( + new XElement("GrandChild", + new XAttribute("ANewAttribute", 999), + (string)el + ) + ); + + // replace Other with NewOther, add new child elements around original content + foreach (var el in root.Elements("Other")) + el.AddAnnotation( + new XElement("NewOther", + new XElement("MyNewChild", 1), + // same idea as xsl:apply-templates + new XElement(xf + "ApplyTransforms"), + new XElement("ChildThatComesAfter") + ) + ); + + // change name of element that has mixed content + root.Descendants("SomeMixedContent").First().AddAnnotation( + new XElement("MixedContent", + new XElement(xf + "ApplyTransforms") + ) + ); + + // replace with + foreach (var el in root.Descendants("b")) + el.AddAnnotation( + new XElement("Bold", + new XElement(xf + "ApplyTransforms") + ) + ); + + // replace with + foreach (var el in root.Descendants("i")) + el.AddAnnotation( + new XElement("Italic", + new XElement(xf + "ApplyTransforms") + ) + ); + + Console.WriteLine("Before Transform"); + Console.WriteLine("----------------"); + Console.WriteLine(root); + Console.WriteLine(); + Console.WriteLine(); + XElement newRoot = XForm(root); + + Console.WriteLine("After Transform"); + Console.WriteLine("----------------"); + Console.WriteLine(newRoot); + } +} +``` + +```vb +Imports System.Collections.Generic +Imports System.Linq +Imports System.Text +Imports System.Xml +Imports System.Xml.Linq + +Imports + +Module Module1 + Dim at As XName = GetXmlNamespace(xf) + "ApplyTransforms" + + ' Build a transformed XML tree per the annotations. + Function XForm(ByVal source As XElement) As XElement + If source.Annotation(Of XElement)() IsNot Nothing Then + Dim anno As XElement = source.Annotation(Of XElement)() + Return _ + <<%= anno.Name.ToString() %>> + <%= anno.Attributes() %> + <%= anno.Nodes().Select(Function(n As XNode) _ + GetSubNodes(n, source)) %> + + Else + Return _ + <<%= source.Name %>> + <%= source.Attributes() %> + <%= source.Nodes().Select(Function(n) GetExpandedNodes(n)) %> + + End If + End Function + + Private Function GetSubNodes(ByVal n As XNode, ByVal s As XElement) As Object + Dim annoEl As XElement = TryCast(n, XElement) + If annoEl IsNot Nothing Then + If annoEl.Name = at Then + Return s.Nodes().Select(Function(n2 As XNode) GetExpandedNodes(n2)) + End If + End If + Return n + End Function + + Private Function GetExpandedNodes(ByVal n2 As XNode) As XNode + Dim e2 As XElement = TryCast(n2, XElement) + If e2 Is Nothing Then + Return n2 + Else + Return XForm(e2) + End If + End Function + + Sub Main() + Dim root As XElement = _ + + + 1 + 2 + + 3 + 4 + + This is an element that has some mixed content + 42 + + + ' Each of the following serves the same semantic purpose as + ' XSLT templates and sequence constructors. + + ' Replace Child with NewChild. + For Each el In root. + el.AddAnnotation(<%= CStr(el) %>) + Next + + ' Replace first GC with GrandChild, add an attribute. + For Each el In root....Take(1) + el.AddAnnotation(<%= CStr(el) %>) + Next + + ' Replace Other with NewOther, add new child elements around original content. + For Each el In root. + el.AddAnnotation( _ + + 1 + <<%= at %>> + + ) + Next + + ' Change name of element that has mixed content. + root...(0).AddAnnotation( _ + <<%= at %>>) + + ' Replace with . + For Each el In root... + el.AddAnnotation(<<%= at %>>) + Next + + ' Replace with . + For Each el In root... + el.AddAnnotation(<<%= at %>>) + Next + + Console.WriteLine("Before Transform") + Console.WriteLine("----------------") + Console.WriteLine(root) + Console.WriteLine(vbNewLine) + Dim newRoot As XElement = XForm(root) + + Console.WriteLine("After Transform") + Console.WriteLine("----------------") + Console.WriteLine(newRoot) + End Sub +End Module +``` + +This example produces the following output: + +```output +Before Transform +---------------- + + + 1 + 2 + + 3 + 4 + + This is an element that has some mixed content + 42 + + +After Transform +---------------- + + + 1 + 2 + + 1 + 3 + 4 + + + This is an element that has some mixed content + 42 + +``` diff --git a/docs/standard/linq/use-xslt-transform-xml-tree.md b/docs/standard/linq/use-xslt-transform-xml-tree.md new file mode 100644 index 0000000000000..f3eafbfdba4f1 --- /dev/null +++ b/docs/standard/linq/use-xslt-transform-xml-tree.md @@ -0,0 +1,120 @@ +--- +title: Use XSLT to transform an XML tree - LINQ to XML +description: Learn to use XSLT to transform an XML tree, using XmlReader to read and XmlWriter to write. +ms.date: 07/20/2015 +dev_langs: + - "csharp" + - "vb" +ms.assetid: 373a2699-d4c5-471b-9bda-c1f0ab73b477 +--- +# Use XSLT to transform an XML tree (LINQ to XML) + +You can use XSLT to transform an XML tree, using to read and to write. + +## Example: Use XSLT to transform an XML tree, using `XMLReader` to read and `XMLWriter` to write + +This example creates an XML tree and uses XSLT to transform it. It makes use of an to read the original tree, and an to write the transformed version. + +It starts by creating: + +- An XML tree. +- An of the XML tree. +- A new document to hold the XSLT output. +- An to write the transformed tree to the new document. + +It then invokes an XSLT transformation that uses the to read the original XML tree, and the to write the transformed tree to the new document. + +```csharp +string xslt = @" + + + + + + + + + + + + "; + +var oldDocument = new XDocument( + new XElement("Parent", + new XElement("Child1", "Child1 data"), + new XElement("Child2", "Child2 data") + ) +); + +var newDocument = new XDocument(); + +using (var stringReader = new StringReader(xslt)) +{ + using (XmlReader xsltReader = XmlReader.Create(stringReader)) + { + var transformer = new XslCompiledTransform(); + transformer.Load(xsltReader); + using (XmlReader oldDocumentReader = oldDocument.CreateReader()) + { + using (XmlWriter newDocumentWriter = newDocument.CreateWriter()) + { + transformer.Transform(oldDocumentReader, newDocumentWriter); + } + } + } +} + +string result = newDocument.ToString(); +Console.WriteLine(result); +``` + +```vb +Dim xslMarkup As XDocument = _ + + + + + + + + + + + + + + +Dim xmlTree As XElement = _ + + Child1 data + Child2 data + + +Dim newTree As XDocument = New XDocument() + +Using writer As XmlWriter = newTree.CreateWriter() + ' Load the style sheet. + Dim xslt As XslCompiledTransform = _ + New XslCompiledTransform() + xslt.Load(xslMarkup.CreateReader()) + + ' Execute the transform and output the results to a writer. + xslt.Transform(xmlTree.CreateReader(), writer) +End Using + +Console.WriteLine(newTree) +``` + +This example produces the following output: + +```xml + + Child1 data + Child2 data + +``` + +## See also + +- +- diff --git a/docs/standard/linq/xml-shape-wordprocessingml-documents.md b/docs/standard/linq/xml-shape-wordprocessingml-documents.md index 8523a6d639a3b..3bae14cde96e2 100644 --- a/docs/standard/linq/xml-shape-wordprocessingml-documents.md +++ b/docs/standard/linq/xml-shape-wordprocessingml-documents.md @@ -14,9 +14,9 @@ This article introduces the XML shape of a WordprocessingML document. ## Microsoft Office formats -The native file format for the 2007 Microsoft Office system is Office Open XML (commonly called Open XML). Open XML is an XML-based format that is an Ecma standard and is currently going through the ISO-IEC standards process. The markup language for word processing files within Open XML is called WordprocessingML. This tutorial uses WordprocessingML source files as input for the examples. +The native file format for the 2007 Microsoft Office system is Office Open XML (commonly called Open XML). Open XML is an XML-based format that's an Ecma standard and is currently going through the ISO-IEC standards process. The markup language for word processing files within Open XML is called WordprocessingML. This tutorial uses WordprocessingML source files as input for the examples. -If you're using Microsoft Office 2003, you can save documents in the Office Open XML format if you have installed the Microsoft Office Compatibility Pack for Word, Excel, and PowerPoint 2007 File Formats. +If you're using Microsoft Office 2003, you can save documents in the Office Open XML format if you've installed the Microsoft Office Compatibility Pack for Word, Excel, and PowerPoint 2007 File Formats. ## The shape of WordprocessingML documents diff --git a/docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md b/docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md deleted file mode 100644 index 01bf83d1c607b..0000000000000 --- a/docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-datacontractserializer.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: "How to: Serialize Using DataContractSerializer" -ms.date: 07/20/2015 -ms.assetid: ecaea518-8a0f-4249-b4e5-9b3fb0cdd8ad ---- -# How to: Serialize Using DataContractSerializer (Visual Basic) -This topic shows an example that serializes and deserializes using . - -## Example - The following example creates a number of objects that contain objects. It then serializes them to text files, and then deserializes them from the text files. - -```vb -Imports System -Imports System.Xml -Imports System.Xml.Linq -Imports System.IO -Imports System.Runtime.Serialization - -Public Class XLinqTest - Shared Sub Main() - Test(Of XElement)(CreateXElement()) - Test(Of XElementContainer)(New XElementContainer()) - Test(Of XElementNullContainer)(New XElementNullContainer()) - End Sub - - Public Shared Sub Test(Of T)(ByRef obj) - Dim s As DataContractSerializer = New DataContractSerializer(GetType(T)) - Using fs As FileStream = File.Open("test" & GetType(T).Name & ".xml", FileMode.Create) - Console.WriteLine("Testing for type: {0}", GetType(T)) - s.WriteObject(fs, obj) - End Using - - Using fs As FileStream = File.Open("test" & GetType(T).Name & ".xml", FileMode.Open) - Dim s2 As Object = s.ReadObject(fs) - If s2 Is Nothing Then - Console.WriteLine(" Deserialized object is null (Nothing in VB)") - Else - Console.WriteLine(" Deserialized type: {0}", s2.GetType()) - End If - End Using - End Sub - - Public Shared Function CreateXElement() As XElement - Return New XElement(XName.Get("NameInNamespace", "http://www.adventure-works.org")) - End Function -End Class - - _ -Public Class XElementContainer - _ - Public member As XElement - - Public Sub XElementContainer() - member = XLinqTest.CreateXElement() - End Sub -End Class - - _ -Public Class XElementNullContainer - _ - Public member As XElement - - Public Sub XElementNullContainer() - member = Nothing - End Sub -End Class -``` - - This example produces the following output: - -```console -Testing for type: System.Xml.Linq.XElement - Deserialized type: System.Xml.Linq.XElement -Testing for type: XElementContainer - Deserialized type: XElementContainer -Testing for type: XElementNullContainer - Deserialized type: XElementNullContainer -``` - -## See also - -- [Serializing Object Graphs that Contain XElement Objects (Visual Basic)](serializing-object-graphs-that-contain-xelement-objects.md) diff --git a/docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md b/docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md deleted file mode 100644 index 6c17a45d752f0..0000000000000 --- a/docs/visual-basic/programming-guide/concepts/linq/how-to-serialize-using-xmlserializer.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: "How to: Serialize Using XmlSerializer" -ms.date: 07/20/2015 -ms.assetid: cace24eb-0f43-4016-8e4b-199e5ef73a1c ---- -# How to: Serialize Using XmlSerializer (Visual Basic) -This topic shows an example that serializes and deserializes using . - -## Example - The following example creates a number of objects that contain objects. It then serializes them to a memory stream, and then deserializes them from the memory stream. - -```vb -Imports System -Imports System.Xml -Imports System.Xml.Linq -Imports System.IO -Imports System.Runtime.Serialization -Imports System.Xml.Serialization - -Public Class XElementContainer - Public member As XElement - - Public Sub XElementContainer() - member = XLinqTest.CreateXElement() - End Sub - - Overrides Function ToString() As String - Return member.ToString() - End Function -End Class - -Public Class XElementNullContainer - Public member As XElement - - Public Sub XElementNullContainer() - member = Nothing - End Sub -End Class - -Public Class XLinqTest - Shared Sub Main() - Test(Of XElementNullContainer)(New XElementNullContainer()) - Test(Of XElement)(CreateXElement()) - Test(Of XElementContainer)(New XElementContainer()) - End Sub - - Public Shared Function CreateXElement() As XElement - Dim ns As XNamespace = "http://www.adventure-works.com" - Return New XElement(ns + "aw") - End Function - - Public Shared Sub Test(Of T)(ByRef obj) - Using stream As New MemoryStream() - Dim s As XmlSerializer = New XmlSerializer(GetType(T)) - Console.WriteLine("Testing for type: {0}", GetType(T)) - s.Serialize(XmlWriter.Create(stream), obj) - stream.Flush() - stream.Seek(0, SeekOrigin.Begin) - Dim o As Object = s.Deserialize(XmlReader.Create(stream)) - Console.WriteLine(" Deserialized type: {0}", o.GetType()) - End Using - End Sub -End Class -``` - - This example produces the following output: - -```console -Testing for type: XElementNullContainer - Deserialized type: XElementNullContainer -Testing for type: System.Xml.Linq.XElement - Deserialized type: System.Xml.Linq.XElement -Testing for type: XElementContainer - Deserialized type: XElementContainer -``` - -## See also - -- [Serializing Object Graphs that Contain XElement Objects (Visual Basic)](serializing-object-graphs-that-contain-xelement-objects.md) diff --git a/docs/visual-basic/programming-guide/concepts/linq/linq-to-xml-security.md b/docs/visual-basic/programming-guide/concepts/linq/linq-to-xml-security.md deleted file mode 100644 index 3788f2690125b..0000000000000 --- a/docs/visual-basic/programming-guide/concepts/linq/linq-to-xml-security.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: "LINQ to XML Security" -ms.date: 07/20/2015 -ms.assetid: d99b4af2-d447-4a3b-991b-6da0231a8637 ---- -# LINQ to XML Security (Visual Basic) -This topic describes security issues associated with LINQ to XML. In addition, it provides some guidance for mitigating security exposure. - -## LINQ to XML Security Overview - LINQ to XML is designed more for programming convenience than for server-side applications with stringent security requirements. Most XML scenarios consist of processing trusted XML documents, rather than processing untrusted XML documents that are uploaded to a server. LINQ to XML is optimized for these scenarios. - - If you must process untrusted data from unknown sources, Microsoft recommends that you use an instance of the class that has been configured to filter out known XML denial of service (DoS) attacks. - - If you have configured an to mitigate denial of service attacks, you can use that reader to populate a LINQ to XML tree and still benefit from the programmer productivity enhancements of LINQ to XML. Many mitigation techniques involve creating readers that are configured to mitigate the security issue, and then instantiating an XML tree through the configured reader. - - XML is intrinsically vulnerable to denial of service attacks because documents are unbounded in size, depth, element name size, and more. Regardless of the component that you use to process XML, you should always be prepared to recycle the application domain if it uses excessive resources. - -## Mitigation of XML, XSD, XPath, and XSLT Attacks - LINQ to XML is built upon and . LINQ to XML supports XSD and XPath through extension methods in the and namespaces. Using the , , and classes in conjunction with LINQ to XML, you can invoke XSLT to transform XML trees. - - If you are operating in a less secure environment, there are a number of security issues that are associated with XML and the use of the classes in , , , and . These issues include, but are not limited to, the following: - -- XSD, XPath, and XSLT are string-based languages in which you can specify operations that consume a lot of time or memory. It is the responsibility of application programmers who take XSD, XPath, or XSLT strings from untrusted sources to validate that the strings are not malicious, or to monitor and mitigate the possibility that evaluating these strings will lead to excessive system resource consumption. - -- XSD schemas (including inline schemas) are inherently vulnerable to denial of service attacks; you should not accept schemas from untrusted sources. - -- XSD and XSLT can include references to other files, and such references can result in cross-zone and cross-domain attacks. - -- External entities in DTDs can result in cross-zone and cross-domain attacks. - -- DTDs are vulnerable to denial of service attacks. - -- Exceptionally deep XML documents can pose denial of service issues; you might want to limit the depth of XML documents. - -- Do not accept supporting components, such as , , and objects, from untrusted assemblies. - -- Read data in chunks to mitigate large document attacks. - -- Script blocks in XSLT style sheets can expose a number of attacks. - -- Validate carefully before constructing dynamic XPath expressions. - -## LINQ to XML Security Issues - The security issues in this topic are not presented in any particular order. All issues are important and should be addressed as appropriate. - - A successful elevation of privilege attack gives a malicious assembly more control over its environment. A successful elevation of privilege attack can result in disclosure of data, denial of service, and more. - - Applications should not disclose data to users who are not authorized to see that data. - - Denial of service attacks cause the XML parser or LINQ to XML to consume excessive amounts of memory or CPU time. Denial of service attacks are considered to be less severe than elevation of privilege attacks or disclosure of data attacks. However, they are important in a scenario where a server needs to process XML documents from untrusted sources. - -### Exceptions and Error Messages Might Reveal Data - The description of an error might reveal data, such as the data being transformed, file names, or implementation details. Error messages should not be exposed to callers that are not trusted. You should catch all errors and report errors with your own custom error messages. - -### Do Not Call CodeAccessPermissions.Assert in an Event Handler - An assembly can have lesser or greater permissions. An assembly that has greater permissions has greater control over the computer and its environments. - - If code in an assembly with greater permissions calls in an event handler, and then the XML tree is passed to a malicious assembly that has restricted permissions, the malicious assembly can cause an event to be raised. Because the event runs code that is in the assembly with greater permissions, the malicious assembly would then be operating with elevated privileges. - - Microsoft recommends that you never call in an event handler. - -### DTDs are Not Secure - Entities in DTDs are inherently not secure. It is possible for a malicious XML document that contains a DTD to cause the parser to use all memory and CPU time, causing a denial of service attack. Therefore, in LINQ to XML, DTD processing is turned off by default. You should not accept DTDs from untrusted sources. - - One example of accepting DTDs from untrusted sources is a Web application that allows Web users to upload an XML file that references a DTD and a DTD file. Upon validation of the file, a malicious DTD could execute a denial of service attack on your server. Another example of accepting DTDs from untrusted sources is to reference a DTD on a network share that also allows anonymous FTP access. - -### Avoid Excessive Buffer Allocation - Application developers should be aware that extremely large data sources can lead to resource exhaustion and denial of service attacks. - - If a malicious user submits or uploads a very large XML document, it could cause LINQ to XML to consume excessive system resources. This can constitute a denial of service attack. To prevent this, you can set the property, and create a reader that is then limited in the size of document that it can load. You then use the reader to create the XML tree. - - For example, if you know that the maximum expected size of your XML documents coming from an untrusted source will be less than 50K bytes, set to 100,000. This will not encumber your processing of XML documents, and at the same time it will mitigate denial of service threats where documents might be uploaded that would consume large amounts of memory. - -### Avoid Excess Entity Expansion - One of the known denial of service attacks when using a DTD is a document that causes excessive entity expansion. To prevent this, you can set the property, and create a reader that is then limited in the number of characters that result from entity expansion. You then use the reader to create the XML tree. - -### Limit the Depth of the XML Hierarchy - One possible denial of service attack is when a document is submitted that has excessive depth of hierarchy. To prevent this, you can wrap a in your own class that counts the depth of elements. If the depth exceeds a predetermined reasonable level, you can terminate the processing of the malicious document. - -### Protect Against Untrusted XmlReader or XmlWriter Implementations - Administrators should verify that any externally supplied or implementations have strong names and have been registered in the machine configuration. This prevents malicious code masquerading as a reader or writer from being loaded. - -### Periodically Free Objects that Reference XName - To protect against certain kinds of attacks, application programmers should free all objects that reference an object in the application domain on a regular basis. - -### Protect Against Random XML Names - Applications that take data from untrusted sources should consider using an that is wrapped in custom code to inspect for the possibility of random XML names and namespaces. If such random XML names and namespaces are detected, the application can then terminate the processing of the malicious document. - - You might want to limit the number of names in any given namespace (including names in no namespace) to a reasonable limit. - -### Annotations Are Accessible by Software Components that Share a LINQ to XML Tree - LINQ to XML could be used to build processing pipelines in which different application components load, validate, query, transform, update, and save XML data that is passed between components as XML trees. This can help optimize performance, because the overhead of loading and serializing objects to XML text is done only at the ends of the pipeline. Developers must be aware, however, that all annotations and event handlers created by one component are accessible to other components. This can create a number of vulnerabilities if the components have different levels of trust. To build secure pipelines across less trusted components, you must serialize LINQ to XML objects to XML text before passing the data to an untrusted component. - - Some security is provided by the common language runtime (CLR). For example, a component that does not include a private class cannot access annotations keyed by that class. However, annotations can be deleted by components that cannot read them. This could be used as a tampering attack. - -## See also - -- [Programming Guide (LINQ to XML) (Visual Basic)](programming-guide-linq-to-xml.md) diff --git a/docs/visual-basic/programming-guide/concepts/linq/reference-linq-to-xml.md b/docs/visual-basic/programming-guide/concepts/linq/reference-linq-to-xml.md deleted file mode 100644 index 17d1cfeeb7a73..0000000000000 --- a/docs/visual-basic/programming-guide/concepts/linq/reference-linq-to-xml.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "Reference (LINQ to XML)" -ms.date: 07/20/2015 -ms.assetid: 0f4cc4b9-361d-4de2-b4c3-be7cbd5dd47b ---- -# Reference (LINQ to XML) -This topic contains links to the LINQ to XML reference topics. - -## In This Section - For reference documentation for the LINQ to XML classes, see . - - For reference documentation for the extension methods that help you validate XML trees against an XSD file, see . - - For reference documentation for the extension methods that enable you to evaluate XPath queries on an XML tree, see . - -## See also - -- [LINQ to XML (Visual Basic)](linq-to-xml.md) From c8ca680d18b4f926dd3eaa11e34dad04d57594fd Mon Sep 17 00:00:00 2001 From: Jim Kramer Date: Wed, 24 Jun 2020 15:59:58 -0700 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Maira Wenzel --- docs/standard/linq/linq-xml-axes-overview.md | 2 +- docs/standard/linq/namespaces-overview.md | 2 +- docs/standard/linq/serialize-datacontractserializer.md | 2 +- docs/standard/linq/serialize-xmlserializer.md | 2 +- .../linq/use-annotations-transform-linq-xml-trees-xslt-style.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/standard/linq/linq-xml-axes-overview.md b/docs/standard/linq/linq-xml-axes-overview.md index 269cea529107d..b5f176052bff3 100644 --- a/docs/standard/linq/linq-xml-axes-overview.md +++ b/docs/standard/linq/linq-xml-axes-overview.md @@ -6,7 +6,7 @@ ms.assetid: 516792fb-461d-40a8-8a50-9993a51258fc --- # LINQ to XML axes overview -After you've created an XML tree or loaded an XML document into an XML tree, you can query it to find elements and attributes and retrieve their values. You retrieve collections through the *axis methods*, also called *axes*. Some of the axes are methods in the and classes that return collections. Some of the axes are extension methods in the class. The axes that are implemented as extension methods operate on collections, and return collections. +After you've created an XML tree or loaded an XML document into an XML tree, you can query it to find elements and attributes and retrieve their values. You retrieve collections through the *axis methods*, also called *axes*. Some of the axes are methods in the and classes that return collections. Some of the axes are extension methods in the class. The axes that are implemented as extension methods operate on collections and return collections. As described in [XElement class overview](xelement-class-overview.md), an object represents a single element node. The content of an element can be complex (sometimes called structured content), or it can be a simple element. A simple element can be empty or can contain a value. If the node contains structured content, you can use the various axis methods to retrieve enumerations of descendant elements. The most commonly used axis methods are and . diff --git a/docs/standard/linq/namespaces-overview.md b/docs/standard/linq/namespaces-overview.md index 4d74f04957057..b66967464f192 100644 --- a/docs/standard/linq/namespaces-overview.md +++ b/docs/standard/linq/namespaces-overview.md @@ -9,7 +9,7 @@ ms.assetid: 16283322-8238-4918-ab11-802ac6748eb7 This article introduces *XML names*, *XML namespaces*, *XML namespace prefixes*, and the and classes. -XML names are often a source of complexity in XML programming. An XML name consists of an XML namespace (also called an XML namespace URI) and a local name. An XML namespace is similar to a namespace in a .NET Framework-based program. It enables you to uniquely qualify the names of elements and attributes to avoid name conflicts between various parts of an XML document. When you've declared an XML namespace, you can select a local name that only has to be unique within that namespace. +XML names are often a source of complexity in XML programming. An XML name consists of an XML namespace (also called an XML namespace URI) and a local name. An XML namespace is similar to a namespace in a .NET program. It enables you to uniquely qualify the names of elements and attributes to avoid name conflicts between various parts of an XML document. When you've declared an XML namespace, you can select a local name that only has to be unique within that namespace. Another aspect of XML names is XML namespace prefixes, which cause most of the complexity of XML names. These prefixes enable you to create a shortcut for an XML namespace, which makes the XML document more concise and understandable. However, the meaning of an XML prefix depends on context, which adds complexity. For example, the XML prefix `aw` could be associated with one XML namespace in part of an XML tree, and with a different namespace in another part. diff --git a/docs/standard/linq/serialize-datacontractserializer.md b/docs/standard/linq/serialize-datacontractserializer.md index cf7969a71baf6..f7982e46c9246 100644 --- a/docs/standard/linq/serialize-datacontractserializer.md +++ b/docs/standard/linq/serialize-datacontractserializer.md @@ -10,7 +10,7 @@ ms.assetid: 3320ecbf-cdbe-480e-979c-2c14bbef9988 # How to serialize using DataContractSerializer (LINQ to XML) -This article shows an example that serializes and deserializes using . +This article shows an example that serializes and deserializes using in C# and Visual Basic. ## Example: Create objects that contain `XElement` objects, then serialize and deserialize them diff --git a/docs/standard/linq/serialize-xmlserializer.md b/docs/standard/linq/serialize-xmlserializer.md index 2dcead91a8845..6fe20c7f301dc 100644 --- a/docs/standard/linq/serialize-xmlserializer.md +++ b/docs/standard/linq/serialize-xmlserializer.md @@ -10,7 +10,7 @@ ms.assetid: 2e0a0bbc-c548-4fe2-8741-be5a9ccd0cbb # How to serialize using XmlSerializer (LINQ to XML) -This article shows an example that serializes and deserializes using . +This article shows an example that serializes and deserializes using in C# and Visual Basic. ## Example: Create objects that contain `XElement` objects, then serialize and deserialize them diff --git a/docs/standard/linq/use-annotations-transform-linq-xml-trees-xslt-style.md b/docs/standard/linq/use-annotations-transform-linq-xml-trees-xslt-style.md index c800641009802..80fdc19586932 100644 --- a/docs/standard/linq/use-annotations-transform-linq-xml-trees-xslt-style.md +++ b/docs/standard/linq/use-annotations-transform-linq-xml-trees-xslt-style.md @@ -32,7 +32,7 @@ In detail, the approach consists of: - The new element that's added as an annotation can contain new child nodes; it can form a subtree with any desired shape. - There is a special rule: If a child node of the new element is in a different namespace, a namespace that's made up for this purpose (in this example, the namespace is `http://www.microsoft.com/LinqToXmlTransform/2007`), then that child element isn't copied to the new tree. Instead, if the namespace is the above-mentioned special namespace, and the local name of the element is `ApplyTransforms`, then the child nodes of the element in the source tree are iterated, and copied to the new tree (with the exception that annotated child elements are themselves transformed according to these rules). - This is somewhat analogous to the specification of transforms in XSL. The query that selects a set of nodes is analogous to the XPath expression for a template. The code to create the new that's saved as an annotation is analogous to the sequence constructor in XSL, and the `ApplyTransforms` element is analogous in function to the `xsl:apply-templates` element in XSL. -- One advantage to taking this approach is that, as you formulate queries, you're always writing queries on the unmodified source tree. You needn't worry about how modifications to the tree affect the queries that you're writing. +- One advantage to taking this approach is that, as you formulate queries, you're always writing queries on the unmodified source tree. You don't need to worry about how modifications to the tree affect the queries that you're writing. ## Example: Rename all paragraph nodes