@@ -50,7 +50,7 @@ use crate::escape::{
5050 escape, minimal_escape, partial_escape, resolve_predefined_entity, unescape_with,
5151} ;
5252use crate :: name:: { LocalName , QName } ;
53- use crate :: reader:: is_whitespace;
53+ use crate :: reader:: { is_whitespace, name_len } ;
5454use crate :: utils:: write_cow_string;
5555#[ cfg( feature = "serialize" ) ]
5656use crate :: utils:: CowRef ;
@@ -992,6 +992,157 @@ impl<'a> arbitrary::Arbitrary<'a> for BytesCData<'a> {
992992
993993////////////////////////////////////////////////////////////////////////////////////////////////////
994994
995+ /// [Processing instructions][PI] (PIs) allow documents to contain instructions for applications.
996+ ///
997+ /// [PI]: https://www.w3.org/TR/xml11/#sec-pi
998+ #[ derive( Clone , Eq , PartialEq ) ]
999+ pub struct BytesPI < ' a > {
1000+ content : BytesStart < ' a > ,
1001+ }
1002+
1003+ impl < ' a > BytesPI < ' a > {
1004+ /// Creates a new `BytesPI` from a byte sequence in the specified encoding.
1005+ #[ inline]
1006+ pub ( crate ) fn wrap ( content : & ' a [ u8 ] , target_len : usize ) -> Self {
1007+ Self {
1008+ content : BytesStart :: wrap ( content, target_len) ,
1009+ }
1010+ }
1011+
1012+ /// Creates a new `BytesPI` from a string.
1013+ ///
1014+ /// # Warning
1015+ ///
1016+ /// `content` must not contain the `?>` sequence.
1017+ #[ inline]
1018+ pub fn new < C : Into < Cow < ' a , str > > > ( content : C ) -> Self {
1019+ let buf = str_cow_to_bytes ( content) ;
1020+ let name_len = name_len ( & buf) ;
1021+ Self {
1022+ content : BytesStart { buf, name_len } ,
1023+ }
1024+ }
1025+
1026+ /// Ensures that all data is owned to extend the object's lifetime if
1027+ /// necessary.
1028+ #[ inline]
1029+ pub fn into_owned ( self ) -> BytesPI < ' static > {
1030+ BytesPI {
1031+ content : self . content . into_owned ( ) . into ( ) ,
1032+ }
1033+ }
1034+
1035+ /// Extracts the inner `Cow` from the `BytesPI` event container.
1036+ #[ inline]
1037+ pub fn into_inner ( self ) -> Cow < ' a , [ u8 ] > {
1038+ self . content . buf
1039+ }
1040+
1041+ /// Converts the event into a borrowed event.
1042+ #[ inline]
1043+ pub fn borrow ( & self ) -> BytesPI {
1044+ BytesPI {
1045+ content : self . content . borrow ( ) ,
1046+ }
1047+ }
1048+
1049+ /// A target used to identify the application to which the instruction is directed.
1050+ ///
1051+ /// # Example
1052+ ///
1053+ /// ```
1054+ /// # use pretty_assertions::assert_eq;
1055+ /// use quick_xml::events::BytesPI;
1056+ ///
1057+ /// let instruction = BytesPI::new(r#"xml-stylesheet href="style.css""#);
1058+ /// assert_eq!(instruction.target(), b"xml-stylesheet");
1059+ /// ```
1060+ #[ inline]
1061+ pub fn target ( & self ) -> & [ u8 ] {
1062+ self . content . name ( ) . 0
1063+ }
1064+
1065+ /// Content of the processing instruction. Contains everything between target
1066+ /// name and the end of the instruction. A direct consequence is that the first
1067+ /// character is always a space character.
1068+ ///
1069+ /// # Example
1070+ ///
1071+ /// ```
1072+ /// # use pretty_assertions::assert_eq;
1073+ /// use quick_xml::events::BytesPI;
1074+ ///
1075+ /// let instruction = BytesPI::new(r#"xml-stylesheet href="style.css""#);
1076+ /// assert_eq!(instruction.content(), br#" href="style.css""#);
1077+ /// ```
1078+ #[ inline]
1079+ pub fn content ( & self ) -> & [ u8 ] {
1080+ self . content . attributes_raw ( )
1081+ }
1082+
1083+ /// A view of the processing instructions' content as a list of key-value pairs.
1084+ ///
1085+ /// Key-value pairs are used in some processing instructions, for example in
1086+ /// `<?xml-stylesheet?>`.
1087+ ///
1088+ /// Returned iterator does not validate attribute values as may required by
1089+ /// target's rules. For example, it doesn't check that substring `?>` is not
1090+ /// present in the attribute value. That shouldn't be the problem when event
1091+ /// is produced by the reader, because reader detects end of processing instruction
1092+ /// by the first `?>` sequence, as required by the specification, and therefore
1093+ /// this sequence cannot appear inside it.
1094+ ///
1095+ /// # Example
1096+ ///
1097+ /// ```
1098+ /// # use pretty_assertions::assert_eq;
1099+ /// use std::borrow::Cow;
1100+ /// use quick_xml::events::attributes::Attribute;
1101+ /// use quick_xml::events::BytesPI;
1102+ /// use quick_xml::name::QName;
1103+ ///
1104+ /// let instruction = BytesPI::new(r#"xml-stylesheet href="style.css""#);
1105+ /// for attr in instruction.attributes() {
1106+ /// assert_eq!(attr, Ok(Attribute {
1107+ /// key: QName(b"href"),
1108+ /// value: Cow::Borrowed(b"style.css"),
1109+ /// }));
1110+ /// }
1111+ /// ```
1112+ #[ inline]
1113+ pub fn attributes ( & self ) -> Attributes {
1114+ self . content . attributes ( )
1115+ }
1116+ }
1117+
1118+ impl < ' a > Debug for BytesPI < ' a > {
1119+ fn fmt ( & self , f : & mut Formatter ) -> fmt:: Result {
1120+ write ! ( f, "BytesPI {{ content: " ) ?;
1121+ write_cow_string ( f, & self . content . buf ) ?;
1122+ write ! ( f, " }}" )
1123+ }
1124+ }
1125+
1126+ impl < ' a > Deref for BytesPI < ' a > {
1127+ type Target = [ u8 ] ;
1128+
1129+ fn deref ( & self ) -> & [ u8 ] {
1130+ & self . content
1131+ }
1132+ }
1133+
1134+ #[ cfg( feature = "arbitrary" ) ]
1135+ impl < ' a > arbitrary:: Arbitrary < ' a > for BytesPI < ' a > {
1136+ fn arbitrary ( u : & mut arbitrary:: Unstructured < ' a > ) -> arbitrary:: Result < Self > {
1137+ Ok ( Self :: new ( <& str >:: arbitrary ( u) ?) )
1138+ }
1139+ fn size_hint ( depth : usize ) -> ( usize , Option < usize > ) {
1140+ return <& str as arbitrary:: Arbitrary >:: size_hint ( depth) ;
1141+ }
1142+ }
1143+
1144+ ////////////////////////////////////////////////////////////////////////////////////////////////////
1145+
9951146/// Event emitted by [`Reader::read_event_into`].
9961147///
9971148/// [`Reader::read_event_into`]: crate::reader::Reader::read_event_into
@@ -1013,7 +1164,7 @@ pub enum Event<'a> {
10131164 /// XML declaration `<?xml ...?>`.
10141165 Decl ( BytesDecl < ' a > ) ,
10151166 /// Processing instruction `<?...?>`.
1016- PI ( BytesText < ' a > ) ,
1167+ PI ( BytesPI < ' a > ) ,
10171168 /// Document type definition data (DTD) stored in `<!DOCTYPE ...>`.
10181169 DocType ( BytesText < ' a > ) ,
10191170 /// End of XML document.
0 commit comments